JAVA IO流
1 File类
java.io.File类
File
能新建、删除、重命名文件和目录,但File
不能访问文件内容本身。如果需要访问文件内容本身,则需要使用输入/输出流。File
对象可以作为参数传递给流的构造器File
类实现了Serializable
、Comparable<File>
,说明它是支持序列化和排序的。- 路径中的每级目录之间用一个路径分隔符隔开
路径分隔符和系统有关:
● windows和DOS系统默认使用“\”来表示
● UNIX和URL使用“/”来表示
File file = new File("D:\\文件.txt");
1.1 常用构造器
方法名 | 说明 |
---|---|
File(File parent, String child) | 根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例。 |
File(String pathname) | 通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例。 |
File(String parent, String child) | 根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例。 |
File(URI uri) | 通过将给定的 file: URI 转换为一个抽象路径名来创建一个新的 File 实例。 |
1.2 常用方法
方法 | 说明 |
---|---|
创建 | |
createNewFile() | 当且仅当不存在具有此抽象路径名指定名称的文件时,不可分地创建一个新的空文件。 |
mkdir() | 创建此抽象路径名指定的目录。 |
mkdirs() | 创建此抽象路径名指定的目录包括任何必需但不存在的父目录 |
删除 | |
delete() | 删除此抽象路径名表示的文件或目录。 |
重命名 | |
renameTo(File dest) | 把文件重命名为指定的文件路径 |
判断 | |
exists() | 测试此抽象路径名表示的文件或目录是否存在。 |
isDirectory() | 测试此抽象路径名表示的文件是否为目录 |
isFile() | 测试此抽象路径名表示的文件是否为普通文件 |
canRead() | 测试应用程序是否可以读取由此抽象路径名表示的文件。 |
canWrite() | 测试应用程序是否可以修改由此抽象路径名表示的文件。 |
isHidden() | 测试此抽象路径名表示的文件是否隐藏 |
获取 | |
getAbsoluteFile() | 返回此抽象路径名的绝对路径名形式。 |
getAbsolutePath() | 返回此抽象路径名的绝对路径名字符串。 |
getName() | 获取名称 |
getPreant() | 获取上层文件目录路径 |
lastModifiled() | 返回最后一次修改的时间,毫秒值 |
list() | 返回一个字符串数组,命名由此抽象路径名表示的目录中的文件和目录。 |
list(FilenameFilter filter) | 返回一个字符串数组,命名由此抽象路径名表示的目录中满足指定过滤器的文件和目录。 |
listFile() | 返回一个抽象路径名数组,表示由该抽象路径名表示的目录中的文件。 |
length() | 返回由此抽象路径名表示的文件的长度。 |
File类使用实例
package file;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.Arrays;
import java.util.Locale;
public class FileTest {
public static void main(String[] args) throws IOException {
File f = new File("FileTest");
File file = new File("FileTest/FileTest.txt");
File newName = new File("FileTest/newFile.txt");
//判断目录是否存在
System.out.println("文件是否存在: " + f.exists());
//创建目录
if (f.mkdir()) {
System.out.println("文件创建成功!");
}
//判断文件是否存在
System.out.println("文件是否存在: " + file.exists());
//创建文件
if (file.createNewFile()) {
System.out.println("文件创建成功!");
}
//判断该文件是否是目录
if (file.isDirectory()) {
System.out.println("这是一个目录!");
} else if (file.isFile()) {
System.out.println("这是一个文件!");
}
//获取文件绝对路径
System.out.println("文件的绝对路径是: " + file.getAbsolutePath());
//获取上层文件目录路径
System.out.println("上层目录路径为: " + file.getParent());
//获取指定目录下以”.txt“结尾的文件
File[] files = f.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
String fileName = name.toLowerCase(Locale.ROOT);
return fileName.endsWith(".txt");
}
});
//获取指定目录下的文件
System.out.println("-------------------------------------");
System.out.println("当前目录下所有文件为: ");
String[] files1 = f.list();
System.out.println(Arrays.toString(files1));
System.out.println("获取所有.txt文件");
for (File file1 :
files) {
System.out.println(file1);
}
System.out.println("----------------------------------------");
//获取文件大小
System.out.println("文件大小是: " + file.length());
//修改文件名
if (file.renameTo(newName)) {
System.out.println("文件名修改成功");
//获取文件名
System.out.println("修改后文件名为: " + newName.getName());
}
//返回最后修改时间
System.out.println("最后修改时间为: " + newName.lastModified());
//删除文件
if (newName.delete()) {
System.out.println("删除成功");
}
}
}
2 IO流
2.1 字节流
InputStream
与OutputStream
是两个抽象类,是字节流的基类,所有具体的字节流实现类都是分别继承了这两个类。
InputStream
2.1.1 节点流
FileOutputSream
- 创建流对象,建立数据存放文件
FileOutputStream fos = new FileOutStream(new File(“test.txt”))
byte[] bs = {} - 调用流对象的写入方法,将数据写入流
fos.write(bs) - 关闭流资源,并将流中的数据清空到文件中
fos.close()
public class FileOutputStreamTest {
public static void main(String[] args) throws IOException {
// out.txt 不存在, 但是想写, 创建新文件
// out.txt 存在, 将内容清空, 再写入 (从文件头开始写入)
File file = new File("out.txt");
// 打开流, 打开本地磁盘文件
FileOutputStream fos = new FileOutputStream(file);
// append-true, 打开文件, 并写入文件末尾 (追加)
// FileOutputStream fos = new FileOutputStream(file, true);
// 写入1个字节 0000 0000 0000 0000 0110 0000 0100 0000
// fos.write(200);
fos.write(-25);
fos.write(-113);
fos.write(-83);
// 字节数组
byte[] bs = {-25, -113, -83};
// 将指定字节数组的所有字节一起写入文件中
fos.write(bs);
byte[] bs1 = "字符串编码".getBytes();
// 将bs1字节中, 从off开始, 写len个字节
fos.write(bs1, 3, 9);
fos.close(); // 及时释放资源 - finally
}
FileInputSream
- 建立一个流对象,将已存在的一个文件加载进流
FileInputStream fis = new FileInStream(new File(“test.txt”)) - 创建一个临时存放数据的数组
char[] ch = new char[1024]; - 调用流对象的读取方法将流中的数据读入到数组中
fis.read(ch) - 关闭资源
fis.close()
public class FileInputStreamTest {
public static void main(String[] args) throws IOException {
// 如果文件不存在, 抛出 FileNotFoundException
File file = new File("out.txt");
FileInputStream fis = new FileInputStream(file);
byte[] bs = new byte[(int)(file.length())];
System.out.println("bs 的长度: " + bs.length);
// 读一些字节, 存入到 bs 数组中
int len = fis.read(bs);
System.out.println(Arrays.toString(bs));
System.out.println("读出来的个数: " + len);
// 解码, 从bs数组的0位置开始, 一共解码 len 个字节
String str = new String(bs, 0, len, "UTF-8");
System.out.println("读出来的字节解码后: " + str);
fis.close();
}
}
- 在读取文件时,必须保证该文件已存在,否则报异常。
- 定义文件路径时,注意:可以用“/”或者“\”
- 在写入一个文件时,如果使用构造器FileOutputStream(file),则目录下有同名文件将被覆盖
2.1.2 缓冲流
BufferedInputStream
BufferedOutputStream
为了提高数据读写的速度,Java API提供了带缓冲功能的流类,在使用这些流类时,会创建一个内部缓冲区数组,缺省使用8192个字节(8Kb)的缓冲区
缓冲区要套在相应的节点流上
public class BufferedInputStreamTest {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("in.txt");
BufferedInputStream bis = new BufferedInputStream(fis);
// 读一个字节, 存入到 int 类型的 i 中
int i = bis.read();
byte[] bs = new byte[10];
// 读一些字节(最多10个), 存入到bs数组中, 并且实际读出来的字节个数是 len 个
int len = bis.read(bs);
FileOutputStream fos = new FileOutputStream("out.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);
// 写一个字节
bos.write(97);
bos.write("hello".getBytes());
bos.write("hello".getBytes(), 0, 2);
bos.flush();
bos.close();
}
}
2.1.3 对象流
ObjectInputStream
OjbectOutputSteam
- 序列化:用ObjectOutputStream类保存基本类型数据或对象的机制
反序列化:用ObjectInputStream类读取基本类型数据或对象的机制 - 不能序列化static和transient修饰的成员变量
- 序列化
某个类实现了 Serializable 接口
创建一个 ObjectOutputStream
调用 ObjectOutputStream 对象的 writeObject(对象) 方法输出可序列化对象
注意写出一次,操作flush()一次 - 反序列化
创建一个 ObjectInputStream
调用 readObject() 方法读取流中的对象
public class Person implements Serializable {
// 添加了版本号以后, 对象的类可以进行调整
public static final long serialVersionUID = 2l;
private int age;
private String name;
}
Person p1 = new Person(18, "狗蛋");
p1.setSex('男');
FileOutputStream fos = new FileOutputStream("obj.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
// 序列化
oos.writeObject(p1);
oos.close();
FileInputStream fis = new FileInputStream("obj.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
// 反序列化
Person p1 = (Person)ois.readObject();
ois.close();
System.out.println(p1);
对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点。当其它程序获取了这种二进制流,就可以恢复成原来的Java对象
- 序列化好处是可将任何实现了Serializable接口的对象转化为字节数据,使其保存和传输时可被还原
- 凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量:
private static final long serialVersionUID; - Java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常
2.1.4 打印流
PrintStream
public class PrintDemo {
public static void main(String[] args) throws IOException {
// 调⽤系统的打印流,控制台直接输出97
System.out.println(97);
// 创建打印流,指定⽂件的名
PrintStream ps = new PrintStream("ps.txt");
// 设置系统的打印流流向,输出到ps.txt
System.setOut(ps);
// 调⽤系统的打印流,ps.txt中输出97
System.out.println(97);
}
}
2.2 字符流
当使⽤字节流读取⽂本⽂件时,可能会有⼀个⼩问题。就是遇到中⽂字符时,可能不会显示完整的字符,那是因为⼀个中⽂字符可能占⽤多个字节存储。所以 Java 提供⼀些字符流类,以字符为单位读写数据,专⻔⽤于处理⽂本⽂件。
与字节流类似,字符流也有两个抽象基类,分别是Reader
和Writer
。其他的字符流实现类都是继承了这两个类。
2.2.1 节点流
FileReader()
FileReader(File file) :创建⼀个新的 FileReader ,给定要读取的File对象。
FileReader(String fileName) :创建⼀个新的 FileReader ,给定要读取的⽂件的名称。
public class FRRead {
public static void main(String[] args) throws IOException {
// 使⽤⽂件名称创建流对象
FileReader fr = new FileReader("read.txt");
//单字符读取
// 定义变量,保存数据
int b;
// 循环读取
while ((b = fr.read()) != -1) {
System.out.println((char) b);
}
//字符数组读取
// 定义变量,保存有效字符个数
int len;
// 定义字符数组,作为装字符数据的容器
char[] cbuf = new char[2];
// 循环读取
while ((len = fr.read(cbuf)) != -1) {
System.out.println(new String(cbuf));
}
// 关闭资源
fr.close();
}
}
FileWriter()
FileWriter(File file) :创建⼀个新的 FileWriter,给定要读取的File对象。
FileWriter(String fileName) :创建⼀个新的 FileWriter,给定要读取的⽂件的名称。
import java.io.*;
public class FWWriter {
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("fw.txt");
// 写出数据
fw.write(97); // 写出第1个字符
fw.write('b'); // 写出第2个字符
fw.write('C'); // 写出第3个字符
fw.write(30000); // 写出第4个字符,中⽂编码表中30000对应⼀个汉字。
// 字符串转换为字节数组
char[] chars = "程序员".toCharArray();
// 写出字符数组
fw.write(chars); // 程序员
// 写出从索引1开始,2个字符。索引1是'序',两个字符,也就是'序员'。
fw.write(b, 2, 2); // 序员
// 字符串
String msg = "程序员";
// 写出字符数组
fw.write(msg); //程序员
// 写出从索引1开始,2个字符。索引1是'序',两个字符,也就是'序员'。
fw.write(msg, 2, 2); // 序员
/*
*【注意】关闭资源时,与FileOutputStream不同。
* 如果不关闭,数据只是保存到缓冲区,并未保存到⽂件。
*/
fw.close();
}
}
2.2.2 缓冲流
特有方法
字符缓冲流的基本⽅法与普通字符流调用方式⼀致,不再阐述,我们来看它们具备的特有⽅法。
BufferedReader: public String readLine() :读一行文字。
BufferedWriter: public void newLine() :写一行分隔符,由系统属性定义符号。
readLine
方法演示,代码如下:
public class BufferedReaderDemo {
public static void main(String[] args) throws IOException {
// 创建流对象
BufferedReader br = new BufferedReader(new FileReader("in.txt"));
// 定义字符串,保存读取的⼀⾏⽂字
String line = null;
// 循环读取,读取到最后返回null
while ((line = br.readLine()) != null) {
System.out.print(line);
System.out.println("------");
}
// 释放资源
br.close();
}
}
newLine
方法演示,代码如下:
public class BufferedWriterDemo throws IOException {
public static void main(String[] args) throws IOException {
// 创建流对象
BufferedWriter bw = new BufferedWriter(new FileWriter("out.txt"));
// 写出数据
bw.write("Java");
// 写出换⾏
bw.newLine();
bw.write("程序");
bw.newLine();
bw.write("员");
bw.newLine();
// 释放资源
bw.close();
}
}
输出效果:
Java
程序
员
2.2.3 打印流
PrintWriter
public class PrintWriter {
// PrintWriter 8个构造方法
public static void main(String[] args) throws IOException {
// 1.1直接传递一个文件名: 使用默认字符集, 清空原文件, 不会自动刷新缓冲区
PrintWriter pw1 = new PrintWriter("out.txt");
// 1.2传递一个文件名 + 字符集: 使用指定字符集, 清空原文件, 不会自动刷新缓冲区
PrintWriter pw2 = new PrintWriter("out.txt", "GBK");
// 2传递一个文件对象(或者 + 字符集): 效果同 1
// 3.1传递一个字节流: 使用默认字符集, 清空原文件, 不会自动刷新
FileOutputStream fos3 = new FileOutputStream("out.txt");
PrintWriter pw3 = new PrintWriter(fos3);
// 3.2传递一个字节流+自动刷新: 使用默认字符集, 清空原文件, 会自动刷新(println)
FileOutputStream fos4 = new FileOutputStream("out.txt");
PrintWriter pw4 = new PrintWriter(fos4, true);
// 3.3传递一个字节流: 使用默认字符集, 在原文件上追加
FileOutputStream fos5 = new FileOutputStream("out.txt", true);
PrintWriter pw5 = new PrintWriter(fos5, true);
// 4.传递一个字符流(或者 + 自动刷新): 效果同3
// 5.转换流(字符流Writer) OutputStreamWriter
FileOutputStream fos = new FileOutputStream("out.txt", true);
OutputStreamWriter osw = new OutputStreamWriter(fos, "GBK");
PrintWriter pw = new PrintWriter(osw, true);
pw.println("你好, 今天吃了吗? 没吃呢还");
//pw.flush();
}
}
2.2.4 转换流
转换流提供了在字节流和字符流之间的转换
Java API提供了两个转换流:
InputStreamReader
:将InputStream转换为Reader
OutputStreamWriter
:将Writer转换为OutputStream
InputStreamReader
- 实现将字节的输入流按指定字符集转换为字符的输入流
- 构造器
public InputStreamReader(InputStream in)
public InputSreamReader(InputStream in,String charsetName)
OutputStreamWriter
- 实现将字符的输出流按指定字符集转换为字节的输出流
- 构造器
public OutputStreamWriter(OutputStream out)
public OutputSreamWriter(OutputStream out,String charsetName)
FileInputStream fis = new FileInputStream("in.txt");
FileOutputStream fos = new FileOutputStream("out.txt");
InputStreamReader isr = new InputStreamReader(fis, "GBK");
OutputStreamWriter osw = new OutputStreamWriter(fos, "GBK");
BufferedReader br = new BufferedReader(isr);
BufferedWriter bw = new BufferedWriter(osw);
String str = null;
while ((str = br.readLine()) != null) {
bw.write(str);
bw.newLine();
bw.flush();
}
bw.close();
br.close();