Java I/O
IO 4 个抽象类:InputStream、OutputStream、Reader、Writer
InputStream、OutputStream操作字节byte[] 读取,写入。
Reader、Writer 操作字符char[] 读取写入。
一 字节流
1. InputStream
- int read():读取数据
- int read(byte b[], int off, int len):从第 off 位置开始读,读取 len 长度的字节,然后放入数组 b 中
- long skip(long n):跳过指定个数的字节
- int available():返回可读的字节数
- void close():关闭流,释放资源
FileInputStream类
- 读取字节:read()方法会读取一个字节并返回其整数表示。如果已经到达文件的末尾,则返回 -1。如果在读取时发生错误,则会抛出 IOException 异常。
// 创建一个 FileInputStream 对象
FileInputStream fis = new FileInputStream("test.txt");
// 读取文件内容
int data;
while ((data = fis.read()) != -1) {
System.out.print((char) data);
}
// 关闭输入流
fis.close();
- 使用字节数组读取:read(byte[] b) 方法会从输入流中最多读取 b.length 个字节,并将它们存储到缓冲区数组 b 中。
// 创建一个 FileInputStream 对象
FileInputStream fis = new FileInputStream("test.txt");
// 读取文件内容到缓冲区
byte[] buffer = new byte[1024];
int count;
while ((count = fis.read(buffer)) != -1) {
System.out.println(new String(buffer, 0, count));
}
// 关闭输入流
fis.close();
FileOutputStream类
- 如果文件不存在,则创建一个新文件;如果文件已经存在,则覆盖原有文件。
String filename = "example.txt";
FileOutputStream fos = new FileOutputStream(filename, true); // 追加模式
String content = "this is content\n"; // 只使用换行符
fos.write(content.getBytes());
fos.close();
- FileOutputStream 写入字节数据
write(int b)
write(byte[] b) // 写入字节数组
write(byte[] b,int off,int len) //从`off`索引开始,`len`个字节 写入指定长度字节数组
使用FileOutputStream,FileInputStream 复制文件
public static void copyFile(String source,String dest) throws FileNotFoundException, IOException{
FileInputStream fis = null;
FileOutputStream fos = null;
try {
// 文件输出流,复制文件
fos = new FileOutputStream(dest);
// 文件输入流,源文件
fis = new FileInputStream(source);
// 创建一个缓冲区数组以存储读取的数据
byte[] buffer = new byte[1024];
int count;
// 读取原始图片文件并将数据写入复制后的图片文件
while ((count = fis.read(buffer)) != -1) {
fos.write(buffer, 0, count);
}
fis.read(new byte[1024]);
} catch (IOException e) {
System.out.print("Exception");
} finally {
fos.close();
fis.close();
}
}
二 字符流
字符流是一种用于读取和写入字符数据的输入输出流。与字节流不同,字符流以字符为单位读取和写入数据,而不是以字节为单位。常用来处理文本信息。
1. Reader
- int read():读取单个字符
- int read(char cbuf[], int off, int len):从第 off 位置开始读,读取 len 长度的字符,然后放入数组 b 中
- long skip(long n):跳过指定个数的字符
- int ready():是否可以读了
- void close():关闭流,释放资源
FileReader
FileReader构造方法
// 使用File对象创建流对象
File file = new File("a.txt");
FileReader fr = new FileReader(file);
// 使用文件名称创建流对象
FileReader fr = new FileReader("b.txt");
FileReader读取字符数据
读取字符:read方法,每次可以读取一个字符,返回读取的字符(转为 int 类型),当读取到文件末尾时,返回-1。代码示例如下:
// 使用文件名称创建流对象
FileReader fr = new FileReader("abc.txt");
// 定义变量,保存数据
int b;
// 循环读取
while ((b = fr.read())!=-1) {
System.out.println((char)b);
}
// 关闭资源
fr.close();
读取指定长度的字符:read(char[] cbuf, int off, int len),并将其存储到字符数组中。其中,cbuf 表示存储读取结果的字符数组,off 表示存储结果的起始位置,len 表示要读取的字符数。代码示例如下:
File textFile = new File("docs/约定.md");
// 给一个 FileReader 的示例
// try-with-resources FileReader
try(FileReader reader = new FileReader(textFile);) {
// read(char[] cbuf)
char[] buffer = new char[1024];
int len;
while ((len = reader.read(buffer, 0, buffer.length)) != -1) {
System.out.print(new String(buffer, 0, len));
}
}
2. Writer
- void write(int c): 写入一个字符
- void write( char cbuf[], int off, int len): 将数组 cbuf 中的从 off 位置开始,长度为 len 的字符写入
- void flush(): 强制刷新,将缓冲区的数据写入
- void close():关闭流
FileWriter
FileWriter 构造方法
// 第一种:使用File对象创建流对象
File file = new File("a.txt");
FileWriter fw = new FileWriter(file);
// 第二种:使用文件名称创建流对象
FileWriter fw = new FileWriter("b.txt");
写入字符
try (FileWriter fw = new FileWriter("b.txt", true)) {
// 写入字符:write(int b) 方法,每次可以写出一个字符,代码示例如下:
fw.write(72); // 写入字符'H'的ASCII码
fw.write(101); // 写入字符'e'的ASCII码
fw.write(108); // 写入字符'l'的ASCII码
fw.write(108); // 写入字符'l'的ASCII码
fw.write(111); // 写入字符'o'的ASCII码
// 写入字符数组:write(char[] cbuf) 方法,将指定字符数组写入输出流。代码示例如下:
char[] chars = { 'c', 'h', 'a', 'r', '[', ']' };
fw.write(chars); // 将字符数组写入文件
// 写入指定字符数组:write(char[] cbuf, int off, int len) 方法,将指定字符数组的一部分写入输出流。代码示例如下:
char[] chars1 = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!' };
fw.write(chars1, 0, 5); // 将字符数组的前 5 个字符写入文件
// 写入字符串:write(String str) 方法,将指定字符串写入输出流。代码示例如下:
String str = "write String";
fw.write(str); // 将字符串写入文件
fw.write("hello\r\n".toCharArray());
// 追加
fw.append("jinnan");
// 刷新缓冲区,流对象可以继续使用
fw.flush();
// 先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了
fw.close();
}
因为 FileWriter 内置了缓冲区 ByteBuffer,所以如果不关闭输出流,就无法把字符写入到文件中。
如果我们既想写入数据,又想继续使用流,就需要 flush 方法了。
三 字节缓冲流
Java 的缓冲流是对字节流和字符流的一种封装,通过在内存中开辟缓冲区来提高 I/O 操作的效率。Java 通过 BufferedInputStream 和 BufferedOutputStream 来实现字节流的缓冲,通过 BufferedReader 和 BufferedWriter 来实现字符流的缓冲。
缓冲流的工作原理是将数据先写入缓冲区中,当缓冲区满时再一次性写入文件或输出流,或者当缓冲区为空时一次性从文件或输入流中读取一定量的数据。这样可以减少系统的 I/O 操作次数,提高系统的 I/O 效率,从而提高程序的运行效率。
BufferedInputStream & BufferedOutputStream
构造:
// 创建字节缓冲输入流,先声明字节流
FileInputStream fps = new FileInputStream(b.txt);
BufferedInputStream bis = new BufferedInputStream(fps)
// 创建字节缓冲输入流(一步到位)
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("b.txt"));
// 创建字节缓冲输出流(一步到位)
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("b.txt"));
读取
//从该输入流中读取一个字节
public int read();
//从此字节输入流中给定偏移量处开始将各字节读取到指定的 byte 数组中。
public int read(byte[] b,int off,int len);
输出
//向输出流中输出一个字节
public void write(int b);
//将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此缓冲的输出流。
public void write(byte[] b,int off,int len);
//刷新此缓冲的输出流。这迫使所有缓冲的输出字节被写出到底层输出流中。
public void flush();
byte 类型通常被用于存储二进制数据,例如读取和写入文件、网络传输等场景。在这些场景下,byte 类型的变量可以用来存储数据流中的每个字节,从而进行读取和写入操作。
使用:
BufferedInputStream bis =null;
BufferedOutputStream bos = null;
try{
bis = new BufferedInputStream(new FileInputStream("test.jpg"));
bos= new BufferedOutputStream(new FileOutputStream("copytest3.jpg"));
//缓冲区的空间有 8 个 1024 字节
byte[] bytes = new byte[8*1024];
int data;
while ((data = bis.read(bytes)) != -1) {
bos.write(bytes, 0 , data);
}
}finally{
bis.close();
bos.close();
}
四 字符缓冲流
BufferedReader & BufferedWriter
构造
// 创建字符缓冲输入流
BufferedReader br = new BufferedReader(new FileReader("b.txt"));
// 创建字符缓冲输出流
BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));
- BufferedReader:String readLine(): 读一行数据,读取到最后返回 null
- BufferedWriter:newLine(): 换行,由系统定义换行符。
//readLine
// 创建流对象
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
// 定义字符串,保存读取的一行文字
String line = null;
// 循环读取,读取到最后返回null
while ((line = br.readLine())!=null) {
System.out.print(line);
System.out.println("------");
}
// 释放资源
br.close();
//newLine()
// 创建流对象
BfferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));
// 写出数据
bw.write("周杰伦");
// 写出换行
bw.newLine();
bw.write("陈奕迅");
bw.newLine();
bw.write("李宗盛");
bw.newLine();
bw.write("五月天");
bw.newLine();
// 释放资源
bw.close();
五 转换流
转换流可以将一个字节流包装成字符流,或者将一个字符流包装成字节流。这种转换通常用于处理文本数据,如读取文本文件或将数据从网络传输到应用程序。
编码与解码:
String str = "test String";
// 编码
byte[] bytes = str.getBytes("utf8");
System.out.println("编码: "+bytes);
// 解码
String newStr = new String(bytes,"utf8");
System.out.println("解码: "+newStr);
1. InputStreamReader
将字节流(InputStream)转换为字符流(Reader),同时支持指定的字符集编码方式,从而实现字符流与字节流之间的转换
构造:
InputStreamReader isr = new InputStreamReader(new FileInputStream("in.txt"));
InputStreamReader isr2 = new InputStreamReader(new FileInputStream("in.txt") , "GBK");
InputStreamReader 类的常用方法包括:
- read():从输入流中读取一个字符的数据。
- read(char[] cbuf, int off, int len):从输入流中读取 len 个字符的数据到指定的字符数组 cbuf 中,从 off 位置开始存放。
- ready():返回此流是否已准备好读取。
- close():关闭输入流。
2. OutputStreamWriter
将字符流转换为字节流,是字符流到字节流的桥梁。
构造:
OutputStreamWriter isr = new OutputStreamWriter(new FileOutputStream("a.txt"));
OutputStreamWriter isr2 = new OutputStreamWriter(new FileOutputStream("b.txt") , "GBK");
OutputStreamWriter 类的常用方法包括:
- write(int c):向输出流中写入一个字符的数据。
- write(char[] cbuf, int off, int len):向输出流中写入指定字符数组 cbuf 中的 len 个字符,从 off 位置开始。
- flush():将缓冲区的数据写入输出流中。
- close():关闭输出流。
在使用转换流时,需要指定正确的字符集编码方式,否则可能会导致数据读取或写入出现乱码。
总结:
六 拓展 File
File对象既可以表示文件,也可以表示目录。
File构造方法:
public static void main(String[] args) throws FileNotFoundException, IOException {
//创建一个文件对象,
File f = new File("test.txt");
f.createNewFile(); // 创建文件
//字节写入流
FileOutputStream fos = new FileOutputStream(f);
fos.write("你好".getBytes("utf8"));
System.out.print(
"create file: " + f.getName() + "\n"
+ "getPath: " + f.getPath() + "\n"
+ "getParent: " + f.getParent() + "\n"
+ "AbsolutePath: " + f.getAbsolutePath() + "\n"
+ "canRead: " + f.canRead() + "\n"
+ "length: " + f.length() + "\n"
+ "isDirectory: " + f.isDirectory()+"\n"
+ "isFile: " + f.isFile()+"\n"
+ "exists: " + f.exists());
}
Apache FileUtils 类
//复制文件或目录
File srcFile = new File("path/to/src/file");
File destFile = new File("path/to/dest/file");
// 复制文件
FileUtils.copyFile(srcFile, destFile);
// 复制目录
FileUtils.copyDirectory(srcFile, destFile);
File file = new File("path/to/file");
// 删除文件或目录
FileUtils.delete(file);
File srcFile = new File("path/to/src/file");
File destFile = new File("path/to/dest/file");
// 移动文件或目录
FileUtils.moveFile(srcFile, destFile);
File srcFile = new File("path/to/src/file");
File destFile = new File("path/to/dest/file");
// 移动文件或目录
FileUtils.moveFile(srcFile, destFile);
Hutool FileUtil 类
//copyFile:复制文件。该方法可以将指定的源文件复制到指定的目标文件中。
File dest = FileUtil.file("FileUtilDemo2.java");
FileUtil.copyFile(file, dest);
//move:移动文件或目录。该方法可以将指定的源文件或目录移动到指定的目标文件或目录中。
FileUtil.move(file, dest, true);
//del:删除文件或目录。该方法可以删除指定的文件或目录,如果指定的文件或目录不存在,则会抛出异常。
FileUtil.del(file);
//rename:重命名文件或目录。该方法可以将指定的文件或目录重命名为指定的新名称。
FileUtil.rename(file, "FileUtilDemo3.java", true);
//readLines:从文件中读取每一行数据。
FileUtil.readLines(file, "UTF-8").forEach(System.out::println);
标签:字符,Java,读取,int,写入,IO,new,字节 From: https://www.cnblogs.com/jinnandu/p/18370832