Java之IO流
1、File的使用
- File类的一个对象,代表一个文件或一个文件目录。
- File 能新建、删除、重命名文件和目录,但 File 不能访问文件内容本身。如果需要访问文件内容本身,则需要使用输入/输出流。
- 想要在Java程序中表示一个真实存在的文件或目录,那么必须有一个File对象,但是Java程序中的一个File对象,可能没有一个真实存在的文件或目录。
- File对象可以作为参数传递给流的构造器。
- 常用构造器:
- File(String filePath):以pathname为路径创建File对象,可以是绝对路径或者相对路径。
- 相对路径:相较于某个路径下,指明的路径。(idea是相对于当前module)
- 绝对路径:是一个固定的路径,从盘符开始。
- public File(String parent,String child):以parent为父路径,child为子路径创建File对象。
- public File(File parent,String child):根据一个父File对象和子文件路径创建File对象。
- File(String filePath):以pathname为路径创建File对象,可以是绝对路径或者相对路径。
1 |
|
常用方法
- 获取功能
- 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数组。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public void test(){
//下面两个文件均不存在
File file1 = new File("hello.txt");
File file2 = new File("/home/hello.txt");
System.out.println(file1.getAbsolutePath());// /module/hello.txt
System.out.println(file1.getPath());//hello.txt
System.out.println(file1.getName());//hello.txt
System.out.println(file1.getParent());//null
System.out.println(file1.length());//0
System.out.println(file1.lastModified());//0
System.out.println();
System.out.println(file2.getAbsolutePath());// /home/hello.txt
System.out.println(file2.getPath());// /home/hello.txt
System.out.println(file2.getName());//hello.txt
System.out.println(file2.getParent());// /home
System.out.println(file2.length());//0
System.out.println(file2.lastModified());//0
System.out.println();
//file3得真实存在,其目录为:
// /home/hello
// -->hello.txt
// -->abc
// -->abc.txt
File file3 = new File("/home/hello");
//以下两个方法只适用于文件目录
String[] list = file3.list();
for(String s : list){
System.out.println(s);//打印abc和hello.txt
}
System.out.println();
File[] files = file3.listFiles();
for(File f : files){
System.out.println(f);//打印/home/hello/abc和/home/hello/hello.txt
}
}- 重命名功能
- public boolean renameTo(File dest):把文件重命名为指定的文件路径。
1
2
3
4
5
6
7
8
public void test(){
File file1 = new File("hello.txt");
File file2 = new File("/home/hello/hello.txt");
//要想保证返回true,需要file1在硬盘中是存在的,且file2不能在硬盘中存在。而且返回true后,file1所在文件会消失。
boolean renameTo = file1.renameTo(file2);
System.out.println(renameTo);
}- 判断功能
- public boolean isDirectory():判断是否是文件目录。
- public boolean isFile() :判断是否是文件。
- public boolean exists() :判断是否存在。
- public boolean canRead() :判断是否可读。
- public boolean canWrite() :判断是否可写。
- public boolean isHidden() :判断是否隐藏。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public void test(){
File file1 = new File("hello.txt");
System.out.println(file1.isDirectory());//false
System.out.println(file1.isFile());//true
System.out.println(file1.exists());//true
System.out.println(file1.canRead());//true
System.out.println(file1.canWrite());//true
System.out.println(file1.isHidden());//false
System.out.println();
File file2 = new File("/home");
System.out.println(file2.isDirectory());//true
System.out.println(file2.isFile());//false
System.out.println(file2.exists());//true
System.out.println(file2.canRead());//true
System.out.println(file2.canWrite());//true
System.out.println(file2.isHidden());//false
}- 创建和删除功能
- public boolean createNewFile() :创建文件。若文件存在,则不创建,返回false。
- public boolean mkdir() :创建文件目录。如果此文件目录存在,就不创建了。如果此文件目录的上层目录不存在,也不创建。
- public boolean mkdirs() :创建文件目录。如果上层文件目录不存在,一并创建。
- public boolean delete():删除文件或者文件夹。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public void test() throws IOException {
File file1 = new File("hello.txt");//默认在项目路径下
if(!file1.exists()){
//文件的创建
file1.createNewFile();
System.out.println("创建成功");
}else{//文件存在
file1.delete();
System.out.println("删除成功");
}
//文件目录的创建
File file2 = new File("/tmp/abc/cde");//只存在/tmp
boolean mkdir = file2.mkdir();
if(mkdir){
System.out.println("创建成功1");//不打印
}
boolean mkdir1 = file2.mkdirs();
if(mkdir1){
System.out.println("创建成功2");//打印
}
//要想删除成功,cde文件目录下不能有子目录或文件
File file3 = new File("/tmp/abc/cde");
System.out.println(file3.delete());
}- 获取功能
2、IO流原理及流的分类
流的分类
按操作数据单位不同分为:字节流(8 bit),字符流(16 bit)。
- 对于文本文件(.txt,.java,.c,.cpp),使用字符流处理。
- 对于非文本文件(.jpg,.mp3,.mp4,.avi,.doc,.ppt,…),使用字节流处理。
按数据流的流向不同分为:输入流,输出流。
按流的角色的不同分为:节点流,处理流。
- 节点流:直接从数据源或目的地读写数据。
- 处理流:不直接连接到数据源或目的地,而是“连接”在已存在的流(节点流或处理流)之上,通过对数据的处理为程序提供更为强大的读写功能。缓冲流是处理流的一种。
抽象基类 | 节点流(或文件流) | 缓冲流(处理流的一种) |
---|---|---|
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() |
3、节点流
- 测试FileReader
- read()的理解:返回读入的一个字符。如果达到文件末尾,返回-1。
- 异常的处理:为了保证流资源一定可以执行关闭操作。需要使用try-catch-finally处理。
- 读入的文件一定要存在,否则就会报FileNotFoundException。
1 |
|
- 测试FileWriter
- File对应的硬盘中的文件如果不存在,在输出的过程中,会自动创建此文件。
- File对应的硬盘中的文件如果存在:
- 如果流使用的构造器是:FileWriter(file,false) / FileWriter(file):对原有文件的覆盖。
- 如果流使用的构造器是:FileWriter(file,true):不会对原有文件覆盖,而是在原有文件基础上追加内容。
1 |
|
- 测试FileReader和FileWriter
1 |
|
- 测试FileInputStream
- 使用字节流FileInputStream处理文本文件,可能出现乱码。(例如文件中含有中文的情况)
1 |
|
- 测试FileInputStream和FileOutputStream
- 进行文件复制时,对于文本文件同样适用。
1 |
|
4、缓冲流
当读取数据时,数据按块读入缓冲区,其后的读操作则直接访问缓冲区。
当使用BufferedInputStream读取字节文件时,BufferedInputStream会一次性从文件中读取8192个(8Kb),存在缓冲区中,直到缓冲区装满了,才重新从文件中读取下一个8192个字节数组。
向流中写入字节时,不会直接写到文件,先写到缓冲区中直到缓冲区写满,BufferedOutputStream才会把缓冲区中的数据一次性写到文件里。使用方法flush()可以强制将缓冲区的内容全部写入输出流。
如果是带缓冲区的流对象的close()方法,不但会关闭流,还会在关闭流之前刷新缓冲区,关闭后不能再写出。
测试BufferedStream
1 |
|
- 测试BufferedReader和BufferedWriter
1 |
|
5、转换流
转换流提供了在字节流和字符流之间的转换。
很多时候我们使用转换流来处理文件乱码问题。实现编码和解码的功能。
测试转换流InputStreamReader和OutputStreamWriter。(属于字符流和处理流)
- InputStreamReader:将一个字节的输入流转换为字符的输入流。
- OutputStreamWriter:将一个字节的输出流转换为字符的输出流。
1 |
|
1 |
|
6、标准输入输出流
- System.in和System.out分别代表了系统标准的输入和输出设备。
- System.in的类型是InputStream。
- System.out的类型是PrintStream,其是OutputStream的子类,FilterOutputStream的子类。
- 重定向:通过System类的setIn,setOut方法对默认设备进行改变。
- public static void setIn(InputStream in)。
- public static void setOut(PrintStream out)。
1 | //从键盘输入字符串,要求将读取到的整行字符串转成大写输出。然后继续进行输入操作,直至当输入“e”或者“exit”时,退出程序。 |
7、打印流
- 实现将基本数据类型的数据格式转化为字符串输出。
- 打印流:PrintStream和PrintWriter。
- 提供了一系列重载的print()和println()方法,用于多种数据类型的输出。
- PrintStream和PrintWriter的输出不会抛出IOException异常。
- PrintStream和PrintWriter有自动flush功能。
- PrintStream 打印的所有字符都使用平台的默认字符编码转换为字节。在需要写入字符而不是写入字节的情况下,应该使用 PrintWriter 类。
- System.out返回的是PrintStream的实例。
1 |
|
8、数据流
- 为了方便地操作Java语言的基本数据类型和String的数据,可以使用数据流。
- 数据流有两个类:(用于读取和写出基本数据类型、String类的数据)
- DataInputStream 和 DataOutputStream。
- 分别“套接”在 InputStream 和 OutputStream 子类的流上。
- 测试将内存中的字符串、基本数据类型的变量写出到文件中。
1 |
|
- 测试将文件中存储的基本数据类型变量和字符串读取到内存中,保存在变量中。
1 |
|
9、对象流
- ObjectInputStream和OjbectOutputSteam。
- 用于存储和读取基本数据类型数据或对象的处理流。它的强大之处就是可以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来。
- 序列化:用ObjectOutputStream类保存基本类型数据或对象的机制。对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点。 当其它程序获取了这种二进制流,就可以恢复成原来的Java对象。
- 对象需要满足如下的要求,方可序列化:
- 需要实现接口:Serializable。
- 当前类提供一个全局常量:serialVersionUID。(如果类没有显示定义这个静态常量,它的值是Java运行时环境根据类的内部细节自动生成的。若类的实例变量做了修改,serialVersionUID 可能发生变化。故建议显式声明。)
- 除了当前类需要实现Serializable接口之外,还必须保证其内部所有属性也必须是可序列化的。(默认情况下,基本数据类型可序列化)。
- 对象需要满足如下的要求,方可序列化:
- 反序列化:用ObjectInputStream类读取基本类型数据或对象的机制。
- ObjectOutputStream和ObjectInputStream不能序列化static和transient修饰的成员变量。
- 测试序列化(将内存中的java对象保存到磁盘中或通过网络传输出去):
1 | public class Person implements Serializable{ |
1 |
|
- 测试反序列化(将磁盘文件中的对象还原为内存中的一个java对象)
1 |
|
10、随机存取文件流
- RandomAccessFile 类
- RandomAccessFile 声明在java.io包下,但直接继承于java.lang.Object类。并且它实现了DataInput、DataOutput这两个接口,也就意味着这个类既可以读也可以写。
- RandomAccessFile 类支持 “随机访问” 的方式,程序可以直接跳到文件的任意地方来读、写文件。
- 支持只访问文件的部分内容。
- 可以向已存在的文件后追加内容。
- 如果RandomAccessFile作为输出流时,写出到的文件如果不存在,则在执行过程中自动创建;如果写出到的文件存在,则会对原有文件内容进行覆盖。(默认情况下,从头覆盖)
- 创建 RandomAccessFile 类实例需要指定一个 mode 参数,该参数指定 RandomAccessFile 的访问模式:
- r: 以只读方式打开。
- rw:打开以便读取和写入。
- rwd:打开以便读取和写入;同步文件内容的更新。
- rws:打开以便读取和写入;同步文件内容和元数据的。
- 测试RandomAccessFile的读写
1 |
|
- RandomAccessFile 类对象可以自由移动记录指针:
- long getFilePointer():获取文件记录指针的当前位置。
- void seek(long pos):将文件记录指针定位到 pos 位置。
- 测试RandomAccessFile对文本文件的覆盖
1 |
|
- 测试使用RandomAccessFile实现数据的插入效果
1 |
|