IO流
一、File类的使用
1.创建File类的实例
File(String filePath)
File(String parentPath,String childPath)
File(File parentFile,String childPath)
//构造器1
File file1 = new File("hello.txt");//相对于当前module
File file2 = new File("D:\\workspace_idea1\\JavaSenior\\day08\\he.txt");
System.out.println(file1);
System.out.println(file2);
//构造器2:
File file3 = new File("D:\\workspace_idea1","JavaSenior");
System.out.println(file3);
//构造器3:
File file4 = new File(file3,"hi.txt");
System.out.println(file4);
2.相对路径和绝对路径
- 相对路径:相较于某个路径下,指明的路径。
- 绝对路径:包含盘符在内的文件或文件目录的路径
3.路径分隔符
- Windows:\\
- Unix:/
4.File类
java.io.File
类:文件和文件目录路径的抽象表示形式,与平台无关。- File 能新建、删除、重命名文件和目录,但 File 不能访问文件内容本身。如果需要访问文件内容本身,则需要使用输入/输出流。
- 想要在Java程序中表示一个真实存在的文件或目录,那么必须有一个File对象,但是Java程序中的一个File对象,可能没有一个真实存在的文件或目录。
- File对象可以作为参数传递给流的构造器。
5.File类的常用方法
5.1 File类的获取功能
public String getAbsolutePath()
:获取绝对路径
public String getPath()
:获取路径
public String getName()
:获取名称
public String getParent()
:获取上层文件目录路径。若无,返回null
public long length()
:获取文件长度(即:字节数)。不能获取目录的长度。
public long lastModified()
:获取最后一次的修改时间,毫秒值
public String[] list()
:获取指定目录下的所有文件或者文件目录的名称数组
public File[] listFiles()
:获取指定目录下的所有文件或者文件目录的File数组
5.2 File类的重命名功能
public boolean renameTo(File dest):把文件重命名为指定的文件路径
5.3 File类的判断功能
public boolean isDirectory()
:判断是否是文件目录
public boolean isFile()
:判断是否是文件
public boolean exists()
:判断是否存在
public boolean canRead()
:判断是否可读
public boolean canWrite()
:判断是否可写
public boolean isHidden()
:判断是否隐藏
5.4 File类的创建功能
public boolean createNewFile()
:创建文件。若文件存在,则不创建,返回false。
public boolean mkdir()
:创建文件目录。如果此文件目录存在,就不创建了。如果此文件目录的上层目录不存在,也不创建。
public boolean mkdirs()
:创建文件目录。如果上层文件目录不存在,一并创建。
5.5 File类的删除功能
public boolean delete()
:删除文件或者文件夹
删除注意事项:Java中的删除不走回收站。
要删除一个文件目录,请注意该文件目录内不能包含文件或者文件目录
二、IO流原理及流的分类
1.IO流原理
Java程序中,对于数据的输入/输出操作以“流(stream)” 的方式进行。java.io
包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过标准的方法输入或输出数据。
2.流的分类
- 操作数据单位:字节流、字符流
- 数据的流向:输入流、输出流
- 流的角色:节点流(直接从数据源或目的地读写数据)、处理流(不直接连接到数据源或目的地,而是“连接”在已存在的流(节点流或处理流)之上,通过对数据的处理为程序提供更为强大的读写功能。)
3.流的体系结构
抽象基类 | 节点流(或文件流) | 缓冲流(处理流的一种) |
---|---|---|
InputStream | FileInputStream (read(byte[] buffer)) | BufferedInputStream (read(byte[] buffer)) |
OutputStream | FileOutputStream (write(byte[] buffer,0,len) | BufferedOutputStream (write(byte[] buffer,0,len) / flush() |
Reader | FileReader (read(char[] cbuf)) | BufferedReader (read(char[] cbuf) / readLine()) |
Writer | FileWriter (write(char[] cbuf,0,len) | BufferedWriter (write(char[] cbuf,0,len) / flush() |
三、节点流的文件读写和复制
1将文件读入程序(内存)中:
//1.实例化File类的对象
File file = new File("hello");
//2.流的实例化
FileReader fr = new FileReader(file);
//3.读入的操作
char[] chars = new char[5];
int len;
while((len=fr.read(chars)) != -1){
for (int i = 0; i < len; i++) {
System.out.println(chars[i]);
}
}
//4.资源的关闭
fr.close();
说明:
- read()的理解:返回读入的一个字符。如果达到文件末尾,返回-1
- 异常的处理:为了保证流资源一定可以执行关闭操作。需要使用try-catch-finally处理
- 读入的文件一定要存在,否则就会报FileNotFoundException。
2 从内存中写出数据到硬盘的文件里:
//1.file的实例化
File file = new File("hello1");
//2.流的实例化
fw = new FileWriter(file,true);
//3.写的操作
fw.write("i have a dream");
fw.write("i really have a dream");
//4.资源的关闭
fw.close();
说明:
- 输出操作,对应的File可以不存在的。并不会报异常
- File对应的硬盘中的文件如果不存在,在输出的过程中,会自动创建此文件。
File对应的硬盘中的文件如果存在:
如果流使用的构造器是:FileWriter(file,false) / FileWriter(file):对原有文件的覆盖
如果流使用的构造器是:FileWriter(file,true):不会对原有文件覆盖,而是在原有文件基础上追加内容。
3.复制文件
3.1复制文本(用字符流来处理)
//1.创建File类的对象,指明读入和写出的文件
File srcfile = new File("E:\\javasenior1\\Reflection\\hello");
File desfile = new File("E:\\javasenior1\\Reflection\\hello2");
//2.创建输入流和输出流的对象
FileReader fr = new FileReader(srcfile);
FileWriter fw = new FileWriter(desfile);
//3.复制操作
char[] cbuf = new char[5];
int len;
while ((len=fr.read(cbuf)) != -1){
fw.write(cbuf,0,len);
}
//4.资源的关闭
fw.close();
fr.close();
3.2复制图片(用字节流来处理)
//1.创建File类的对象,指明读入和写出的文件
File srcfile = new File("E:\\javasenior1\\Reflection\\爱情与友情.jpg");
File desfile = new File("E:\\javasenior1\\Reflection\\爱情与友情2.jpg");
//2.创建字节输入流和字节输出流的对象
FileInputStream fis = new FileInputStream(srcfile);
FileOutputStream fos = new FileOutputStream(desfile);
//3.复制操作
byte[] bbuf = new byte[5];
int len;
while ((len=fis.read(bbuf)) != -1){
fos.write(bbuf,0,len);
}
//4.资源的关闭
fis.close();
fos.close();
结论:
- 对于文本文件(.txt,.java,.c,.cpp),使用字符流处理
- 对于非文本文件(.jpg,.mp3,.mp4,.avi,.doc,.ppt,…),使用字节流处理
四、缓冲流的复制
1.缓冲流:
BufferedInputStream
、BufferedOutputStream
、BufferedReader
、BufferedWriter
2.作用:提供流的读取、写入的速度。提高读写速度的原因:内部提供了一个缓冲区
3.处理流,就是**“套接”**在已有的流的基础上。
//1.造文件
File srcfile = new File("E:\\javasenior1\\Reflection\\爱情与友情.jpg");
File destfile = new File("E:\\javasenior1\\Reflection\\爱情与友情3.jpg");
//2.造流
//2.1造节点流
FileInputStream fis = new FileInputStream(srcfile);
FileOutputStream fos = new FileOutputStream(destfile);
//2.2造缓冲流
BufferedInputStream bis = new BufferedInputStream(fis);
BufferedOutputStream bos = new BufferedOutputStream(fos);
//3.复制操作
byte[] buf = new byte[1024];
int len;
while((len=fis.read(buf)) !=-1){
bos.write(buf,0,len);
}
//4.资源的关闭
//有缓冲流的时候只用关闭最外层流即可
bis.close();
bos.close();
注: 资源在关闭时,只需写出关闭最外层的处理流即可。
使用BufferedReader和BufferedWriter实现文本文件的复制:
BufferedReader br = new BufferedReader(new FileReader(new File("E:\\javasenior1\\Reflection\\hello")));
BufferedWriter bw = new BufferedWriter(new FileWriter(new File("E:\\javasenior1\\Reflection\\hello3")));
//方式一:使用char[]数组
// char[] cbuf = new char[1024];
// int len;
// while((len = br.read(cbuf)) != -1){
// bw.write(cbuf,0,len);
// bw.flush();
// }
//方式二:使用String
String data;
while((data = br.readLine()) != null){
//方法一:
// bw.write(data + "\n");//data中不包含换行符
//方法二:
bw.write(data);//data中不包含换行符
bw.newLine();//提供换行的操作
}
五、转换流
转换流提供了在字节流和字符流之间的转换
-
转换流:属于字符流
InputStreamReader
:将一个字节的输入流转换为字符的输入流
OutputStreamWriter
:将一个字符的输出流转换为字节的输出流 -
作用:提供字节流与字符流之间的转换
-
解码:字节、字节数组 —>字符数组、字符串(看不懂的往看得懂的转换)
编码:字符数组、字符串 —> 字节、字节数组(看得懂的往看不懂的转换)
FileInputStream fis = new FileInputStream("dbcp.txt");
InputStreamReader isr = new InputStreamReader(fis, "utf-8");
char[] cbuf = new char[20];
int len;
while((len=isr.read(cbuf)) != -1){
String s = new String(cbuf,0,len);
System.out.print(s);
}
isr.close();
补充:字符编码
起初的编码是有美国制定的ASCII码,但由于汉字等其他国家的汉字,ASCII码并不能完全表示,所以推出了Unicode字符集,Unicode字符集只是定义了字符的集合和唯一编号,Unicode编码,则是对UTF-8、UTF-16等具体编码方案的统称而已,并不是具体的编码方案,只是传输单位不同。
六、其他流
1.输入输出流
InputStream in = System.in;
InputStreamReader isr = new InputStreamReader(in);
BufferedReader br = new BufferedReader(isr);
while(true){
System.out.println("请输入字符串:");
String data = br.readLine();
if("e".equalsIgnoreCase(data)|| "exit".equalsIgnoreCase(data)){
System.out.println("程序结束");
break;
}
String s = data.toUpperCase();
System.out.println(s);
}
br.close();
说明:标准的输入、输出流
System.in:标准的输入流,默认从键盘输入
System.out:标准的输出流,默认从控制台输出
该程序先将输入流转换成缓冲字符流,用于将输入的字符转化成大写形式
2.打印流:PrintStream
和PrintWriter
FileOutputStream fos = new FileOutputStream(new File("D:\\IO\\text.txt"));
// 创建打印输出流,设置为自动刷新模式(写入换行符或字节 '\n' 时都会刷新输出缓冲区)
PrintStream ps = new PrintStream(fos, true);
if (ps != null) {// 把标准输出流(控制台输出)改成文件
System.setOut(ps);
}
for (int i = 0; i <= 255; i++) { // 输出ASCII字符
System.out.print((char) i);
if (i % 50 == 0) { // 每50个数据一行
System.out.println(); // 换行
}
}
ps.close();
说明:单独写for循环内的程序,是将字符输出到内存中。而整个程序指的是将字符写入文件。
3.数据流:DataInputStream
和 DataOutputStream
作用:用于读取或写出基本数据类型的变量或字符串
3.1数据写入
//1.
DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));
//2.
dos.writeUTF("刘建辰");
dos.flush();//刷新操作,将内存中的数据写入文件
dos.writeInt(23);
dos.flush();
dos.writeBoolean(true);
dos.flush();
//3.
dos.close();
将文件中存储的基本数据类型变量和字符串读取到内存中,保存在变量中。
注意点:①读取不同类型的数据的顺序要与当初写入文件时,保存的数据的顺序一致!,即怎么写的怎么读。②每写一次数据就刷新一次
3.2数据读入
//1.
DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));
//2.
String name = dis.readUTF();
int age = dis.readInt();
boolean isMale = dis.readBoolean();
System.out.println("name = " + name);
System.out.println("age = " + age);
System.out.println("isMale = " + isMale);
//3.
dis.close();
4.对象流:ObjectInputStream
和OjbectOutputSteam
用于存储和读取基本数据类型数据或对象的处理流。