本文已参与「新人创作礼」活动,一起开启掘金创作之路。
第十一章 IO流
1.File类的使用
- java.io.File 类:**文件和文件目录路径**的抽象表示形式,和平台无关,声明在java.io下
- File 能新建、删除、重命名文件和目录,但是 File 不能访问文件内容本身,如需要访问文件内容,需要借助输入/输出流
- 想要在Java程序中表示一个真实存在的文件或目录,name必须有一个File对象,但是在Java程序中的一个File对象,可能没有一个真实存在的文件或目录
- File 对象可以作为参数传递给li流的构造器
1.1 File 类的常用方法
-
创建 File 类的对象
- 相对路径 :相较于某个路径下,指明的路径
- 绝对路径:包含盘符在内的文件或文件目录的路径
- 在Windows下路径分隔符用 / 在UNIX下用 \
- 为了避免在不同操作系统出现混淆,java 提供了一个常量,根据操作系统,动态提供分隔符 public static final String separator
//构造器一 File(String filePath) //相对路径 File file1 = new File("Hello.txt"); //绝对路径 File file2 = new File("D:\\Study\\java\\java培训详细版.md"); //使用常量的方式 //"D:" + File.separator + "Study" +File.separator + "java" File.separator + "java培训详细版.md"//构造器二 File(String parentPath,String childPath) File file3 = new File("D:\\Study\\java","Test"); //构造器三 File(File parentFile,String childPath) File file4 = new File(file3,"tset.txt"); -
获取绝对路径 getAbsolutePath()[一等优先级]
//public String getAbsolutePath() System.out.println(file1.getAbsolutePath()); -
获取相对路径 getPath()[一等优先级]
//public String getPath() System.out.println(file1.getPath()); -
获取名称 getName()[一等优先级]
//public String getName() System.out.println(file1.getName()); -
获取上层文件目录路径,没有返回null getParent()[一等优先级]
//public String getParent() System.out.println(file1.getParent()); -
获取文件字节总数 length()[一等优先级]
//public long length() System.out.println(file1.length()); -
获取最后一次修改时间 毫秒值 lastModified()[一等优先级]
//public long lastModified() System.out.println(new Date(file1.lastModified());==以下两个方法适用于文件目录==
-
获取指定目录下所有文件或文件目录的名称数组 list()[特等优先级]
//public String[] list() File file4 = new File("D:\\study"); String[] list = file.list(); for(String s : list){ System.out.println(s); } -
获取指定目录下的所有文件或目录的File数组listFiles()[特等优先级]
//public File[] listFiles() File[] fs = file4.listFiles(); for(File f : fs){ System.out.println(f); } -
得到当前系统的所有根目录listRoots()[特等优先级]
//public static listRoots File[] fs = File.listRoots(); -
把文件重命名为指定的文件路径 renameTo()[高危]
//public boolean renameTo(File dest) File f1 = new File("hello.txt"); File f2 = new File("D:\\Study\\hello.txt"); boolean re = f1.renameTo(f2); System.out.println(re); /* 要想保证是true,需要 f1 在硬盘中存在的,且 f2 不能再硬盘中存在 */==2. File类的判断功能==
-
是否是文件目录 isDirectory()[一等优先级]
//public boolean isDirectory() File f1 = new File("hello.txt"); System.out.println(f1.isDirectory());//false -
是否是文件 isFile()[一等优先级]
System.out.println(f1.isFile()); -
是否存在 exists()[一等优先级]
System.out.println(f1.exists()); -
是否可读 canRead()
System.out.println(f1.canRead()); -
是否可写 canWrite()
System.out.println(f1.canWrite()); -
是否隐藏 isHidden()
System.out.println(f1.isHidden);3. ==File类的创建删除功能==
方法 作用 createNewFile() 创建文件,如果存在返回false不进行创建 mkdir() 创建文件目录,存在则不创建 mkdirs()[高危] 创建文件目录,如果上一级目录不存在,一并创建 delete()[高危] 删除文件或文件夹,不经过回收站 File file = new File("hi.txt"); if(!file.exists()){ file.createNewFile(); }else{ file.delete(); } File file1 = new File("D:\\io\\io1 "); file1.mkdir(); file1.mkdirs();==例题==
判断指定目录下是否有.jpg文件,如果有输出文件名
import java.io.*; public class JpgTest{ public static void main(String[] args){ File srcFile = new File("D:\\Study"); String[] fileNames = srcFile.list(); for(String name : fileNames){ if(name.endsWith(".jpg")){ System.out.println(name); } } } }遍历指定目录下所有文件名称,包括文件目录中的文件
import java.io.*; public class FileTest{ public static void main(String[] args){ File dir = new File("D:\\Study\\Yitu"); printSubFile(dir); } private static void printSubFile(File dir){ File[] subFiles = dir.listFiles(); for(File f : subFiles){ if(f.isDirectory()){ printSubFile(f); }else{ System.out.println(f.getAbsolutePath()); } } } }
2. IO流原理及流的分类
- 用于**处理设备之间的数据传输**,如读/写文件、网络通讯等
- java程序中,对于数据的输入/输出操作以**流(Stream)**的方式进行
- java.io 包下提供了各种 “ 流” 类的接口,用一获取不同种类的数据,并通过**标准的方法**输入或输出数据
-
流的分类
- 按操作数据单位不同:字节流(8 bit)、字符流(16 bit)
- 按数据流的流向不同:输入流、输出流
- 按流的角色不同分为:节点流、处理流
- 字节流读取中文会乱码,因为一个中文占用两个字节,所以需要用字符流读取
抽象基类 字节流 字符流 输入流 InputStream Reader 输出流 OutputStream Writer 分类 字节输入流 字节输出流 字符输入流 字符输出流 抽象基类 ==InputStream== ==OutputStream== ==Reader== ==Writer== 访问文件 ==FileInputStream== ==FileOutputStream== ==FileReader== ==FileWriter== 访问数组 ByteArrayInputStream ByteArrayOutputStream CharArrayReader CharArrayWriter 访问管道 PipedInputStream PipedOutputStream PipedReader PipedWriter 访问字符串 StringReader StringWriter 缓冲流 ==BufferedInputStream== ==BufferedOutputStream== ==BufferrdReader== ==BufferedWriter== 转换流 ==InputStreamReader== ==OutputStreamWriter== 对象流 ==ObjectInputStream== ==ObjectOutputStream== **** FilterInputStream FilterOutputStream FilterReader FilterWriter 打印流 PrintStrem PrintWriter 推回输入流 PushbackInputStream PushbackReader 特殊流 DataInputStream DataOutputStream
2.1FileInputStream/FileOutputStream
-
try-catch-finally
import java.io.*; public class TestFileCopy{ public static void main(String[] args) throws IOException{ FileInputStream fis = null; FileOutputStream fos = null; try{ fis = new FileInputStream("DNF - 痛苦之村列瑟芬.mp3"); fos = new FileOutputStream("DNF - 痛苦之村列瑟芬1.mp3"); byte[] data = new byte[3 << 20]; int len; while((len = fis.read(data)) != -1){ fos.write(data,0,len); } //太慢了 /* while((data = fis.read()) != -1){ fos.write(data); } */ }catch(IOException e){ e.printStackTrace(); }finally{ try{ fis.close(); }catch(IOException e){ e.printStackTrace(); }finally{ try{ fos.close(); }catch(IOException e){ e.printStackTrace(); } } } } } -
TWR 7.0新特性[超级重要:horse:]
import java.io.*; public class TestFileCopyWithTWR{ public static void main(String[] args){ try(FileInputStream fis = new FileInputStream("1.jpg");FileOutputStream fos = new FileOutputStream("2.png")){ byte[] data = new byte[1024]; int len; while((len = fis.read(data)) != -1){ fos.write(data,0,len); } }catch(IOException e){ e.printStackTrace(); } } } -
FileOutputStream的构造方法
FileOutputStream( File f / String name) 这种模式如果有文件则会把源文件删除,在创建新的文件。想要在源文件的基础上追加文件则需要用 FileOutputStream(File f,true)
3 节点流
3.1 FileReader / FileWriter
- FileReader
- read() 返回读入的一个字符,如果达到文件末尾,则返回 -1
- 为了保证流资源一定会执行关闭操作,并需用try-catch-finally捕获异常
import java.io.*;
public class FileReaderTest{
@Test
public void test(){
File file = null;
FileReader fr = null;
try{
//1.实例化 File 类的对象,指明要操作的文件
file = new File("hi.txt");
//2.提供具体的流
fr = new FileReader(file);
//3.数据的读入
int data = fr.read();
while(data != -1){
System.out.print((char)data);
data = fr.read();
}
/*
int data;
while((data = fr.read()) != -1){
System.out.println((char)data);
}
*/
}catch(IOExecption){
e.printStackTrace();
}finally{
try{
//4.流的关闭
if(fr != null)
fr.close();
}catch(IOExecption){
e.printStackTrace();
}
}
}
//对 read() 操作升级,使用 read 的重载方法
@Test
public void testFileReader1{
File file = null;
FileReader fr = null;
try{
//1.File 类的实例化
file = new File("Hi.txt");
//2.FileReader流的实例化
fr = new FileReader(file);
//3.读入操作
//read(char[cbuf]):返回每次读入 cbuf数组中的字符串个数,如果达到文件末尾返回-1
char[] cbuf = new char[5];
int len;
while((len = file.read(cbuf)) != -1){
//方式一
for(int i = 0;i < len;i++){
System.out.print(cbuf[i]);
}
//方式二
String str = new String(cbuf,0,len);
System.out.print(str);
}
}catch(IOExecption e){
e.printStackTrace();
}finally{
//4.资源的关闭
}
}
}
- FileWriter
==说明==
- 输出操作,对应的 File 可以不存在,并不会报异常
File 对应的硬盘中的文件如果不存在,在输出的过程中,会自动创建这个对象
如果存在:①如果流使用的构造器是 FileWriter(file ,false) / FileWriter(file) ,对原有文件覆盖②如果使用的是 FileWriter(file,true) 不会对原有文件覆盖,而是在原有文件基础上追加内容
@Test
public void testFileWriter(){
File file = null;
FileWriter fw = null;
try{
//1. 提供 File 类对象,指明写出到的文件
file = new File("Hi1.txt");
//2.提供 FileWriter 的对象,用于数据写出
fw = new FileWriter(file,false);
//3.写出的操作
fw.write("Hello World!");
}catch(IOExecption e){
e.printStackTrace();
}fianlly{
fw.close();
}
}
==使用 FileWriter 和 FileReader 实现文本文件的复制==
import java.io.*;
//不能用字符流处理图片文件
public class TestFileCopy{
@Test
public void test(){
FileReader fr = null;
FileWriter fw = null;
try{
//1.创建 File 类的对象,指明读入和写出的文件
File srcFile = new File("Hei.txt");
File destFile = new File("Hi.txt");
//2.创建输入流和输出流的对象
fr = new FileReader(srcFile);
fw = new FileWriter(destFile);
//3.数据输入输出操作
char[] c = new char[5];
int len;//记录每次读出来的字符个数
while((len = fr.read(c)) != -1){
//每次写出 len 个字符
fw.write(c,0,len);
}
}catch(IOExecption e){
e.printStackTrace();
}finally{
//4.资源的关闭
try{
if(fw != null)
fw.close();
}catch(IOExecption){
e.printStackTrace();
}finally{
try{
if(fr != null)
fr.close();
}catch(IOExecption){
e.printStackTrace();
}
}
}
}
}
对于文本文件**(.txt .java .c .cpp)**使用字符流处理,对于非文本文件使用字节流处理
3.2BufferedInputStream/BufferedOutputStream
- 提高流的读取,写入速度
-
实现非文本文件的复制
import java.io.*; public class BufferedTest{ @Test public void BUfferedTest(){ FileInuputStream fis = null; FileInuputStream fis = null; BufferedInputStream bis = null; BufferedOutputStream bos = null; try{ //1.造 File 对象 File file1 = new File("hi.jpg"); File file2 = new File("hei.jpg"); //2.造流 //2.1 造节点流 fis = new FileInputStream(file1); fis = new FileOutputStream(file2); //2.2造缓冲流 bis = new BufferedInputStream(fis); bos = new BufferedOutputStream(fos); //3.读取写入 byte[] b = new byte[10]; int len; while((len = bis.read(b)) != -1){ bos.writer(b,o,len); } }finally{ //4.资源关闭 //先关闭外层,再关内层 bos.close(); bis.close(); //关闭外层流的同时,内层流会自动关闭 fw.close(); fr.close(); } } }
3.3 DataInputStream/DataOutputStream
- 都属于**字节流、过滤流**
- 作为过滤流,是为了给原本的节点流添加读写基本数据类型的功能的
- 过滤流不能直接连接文件,只能连接其他的流
- **DataInputStream **不再以-1作为读取结束的标志。如果到了文件结果还尝试进行读取会导致EOFException -> EndOfFileException
import java.io.*;
public class TestDataStream{
public static void main(String[] args)throws Exception{
//我们想要把人物等级保存下来~等到明年春暖花开日 再继续游戏~
/*
int level = 7365;
DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.data"));
dos.writeInt(level);
dos.close();
*/
DataInputStream dis = new DataInputStream(new FileInputStream("data.data"));
int x = dis.readInt();
dis.close();
System.out.println(x);
}
}
3.4 ObjectInputStream/ObjectOutputStream
- 同样是**字节流、过滤流**
- 为了给原本的节点流添加读取对象的功能的
- 如果到达文件结尾会触发EOFException
==注意点==
想要持久化一个对象 必须先要序列化这个类型 如果想要将A类的对象写出到磁盘当中 则A类必须实现序列化接口 implements Serializable 而如果A类当中还有其它引用类型的属性 则这些属性的类型 也要实现序列化接口 否则A对象持久化会出现异常 如果某些属性 无关紧要 不需要保存到文件当中 可以使用transient修饰 transient = 短暂的 转瞬即逝的 = 不参与持久化的 在写出一个对象的时候 transient的属性 将直接写出null 所以这个属性的类型 也就不需要序列化了~
import java.io.*;
import java.text.*;
public class TestObjectStream2{
public static void main(String[] args){
Wish myWish = new Wish("能早点在一起上课~网络教学就是坑!有个屁用!","5v");
System.out.println(myWish);
//请许下自己的愿望 并且将愿望保存在磁盘文件当中
try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("月光宝盒.data"))){
oos.writeObject(myWish);
}catch(Exception e){
e.printStackTrace();
}
}
}
class Wish implements Serializable{//愿望
String content;//愿望的内容
String name;//许愿人姓名
long time;//许下愿望的时间
public Wish(String content,String name){
this.content = content;
this.name = name;
time = System.currentTimeMillis();
}
@Override
public String toString(){
SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd");
return content + "\n\t\t\t" + name +"\n\t\t\t" + f.format(time);
}
}
4 字符流
Reader / Writer 是字符流的抽象基类
4.1FileReader/FileWriter
这两个类只能用来读取文本文件,但是字节流通用语所有文件
.txt .java .html .js .css .jsp .asp .php等
用法用FileInputStream / FileOutputStream类似
4.2 BufferedReader/BufferedWriter
-
BufferedReader / BufferedWriter
- 给原本的流添加一个变长的缓冲空间,从而实现以行为单位的读取
- 文件结束返回null
import java.io.*; public class TestBufferedWriter{ public static void main(String[] args)throws Exception{ //春眠不觉晓 处处闻啼鸟 夜来风雨声 花落知多少 BufferedWriter bw = new BufferedWriter(new FileWriter("鹅鹅鹅.txt")); bw.write("鹅鹅鹅"); bw.newLine();//能够写出当前操作系统所匹配的换行标识 bw.write("鹅项向天歌"); bw.newLine(); bw.write("鹅毛浮绿水"); bw.newLine(); bw.write("鹅可能死了"); bw.close(); } } -
PrintWiter
PrintWriter 和BufferedWriter 相比的优势
- PrintWriter既可以当做节点流 也可以当做过滤流,构造方法允许传入 File对象 / String路径 / 流!
- PrintWriter既可以连接字节流 又可以连接字符流,构造方法既可以传入 FileWriter 也可以传入 FileOutputStream
- 当做节点流使用的时候 构造方法第二个参数可以指定字符编码
new PrintWriter("鹅鹅鹅.txt","utf-8"); - 当做过滤流使用的时候 构造方法第二个参数可以指定自动清空缓冲
new PrintWriter(new FileWriter("abc.txt"),true);//autoFlush - 它的println() = write() + newLine()
import java.io.*; public class TestPrintWriter{ public static void main(String[] args)throws Exception{ PrintWriter pw = new PrintWriter("春晓.txt"); pw.println("春眠不觉晓");//write()+newLine(); pw.println("处处闻啼鸟"); pw.println("夜来风雨声"); pw.print("花落知多少"); pw.close(); } }
5. 转换流
- 转换流提供了在字节流和字符流之间的转换
- 通常使用转换流来处理文件乱码问题,
- 字节大输入流转换成字符输入流**InputStreamReader、字符输出流转换成字节输出流OutputStreamWriter**
public class InputStreamReaderTest{
public static void main(String[] args) throws IOExecption{
FileInputStream fis = new FileInputStream("Test.txt");
InputStreamReader isr = new InputStreamReader(fis);
char[] c = new char[10];
int len;
while((len = isr.read(c)) != -1){
String str = new String(c,0,len);
System.out.println(str);
}
isr.close()
}
}