目录
IO输入流(读取磁盘文件至内存中)
大致分为:字节输入流(以字节方式读取),字符输入流(以字符或一行字符读取),对象输入流(读取为一个对象,应该是吧.....)
常用输入流如下:
java
// 文件字节输入流
FileInputStream fileInputStream = new FileInputStream("文件路径 或 File对象");
// 字节输入缓冲流
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
// 对象输入流
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
// 文件字符输入流
FileReader fileReader = new FileReader("文件路径 或 File对象");
// 字符输入转换流,以指定编码读取文件,第二个参数是格式编码,可以输入字符串,如:"UTF-8","GBK"
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, StandardCharsets.UTF_8);
// 字符输入缓冲流
BufferedReader bufferedReader = new BufferedReader(fileReader 或 inputStreamReader);
输入流和输入缓冲流区别:简单点说缓冲流读取更快,因为它内部有8k缓存空间。
IO输出流(读取内存中的数据写入到磁盘)
大致分为:字节输出流(以字节方式输出),字符输出流(以字符或一行字符输出),对象输出流(输出一个对象到文件中)
常用输入流如下:
java
// 字节输出流
FileOutputStream fileOutputStream = new FileOutputStream("文件路径 或 File对象");
// 字节输出缓冲流
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
// 对象输出流
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
// 字符输出流
FileWriter fileWriter = new FileWriter("文件路径 或 File对象");
// 字符输出转换流,以指定编码写入文件,第二个参数是格式编码,可以输入字符串,如:"UTF-8","GBK"
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, StandardCharsets.UTF_8);
// 字符输出缓冲流
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter 或 outputStreamWriter);
输出流和输出缓冲流区别:简单点说缓冲流写入更快,小文件体现不出来,上G的文件就能体现出来了。
注意:构建输出流时,如果输出文件里面原本有内容,则会被直接清空。
IO流读取文件并写入另一个文件(拷贝)
拷贝D盘的old.txt文件,生成一个新的new.txt文件
用字节输入输出流实现
java
public static void main(String[] args) {
// 原文件(输入文件)
File inputFile = new File("D:/AAA/old.txt");
// 新文件输出路径
File outputParentFile = new File("D:/AAA");
// 新文件(输出文件)
File outputFile = null;
if (!inputFile.exists()) {
String errorMsg = new StringBuffer("原文件不存在:")
.append(inputFile.getAbsolutePath())
.toString();
logger.warn(errorMsg);
throw new RuntimeException(errorMsg);
}
// 输出路径不存在,且创建路径失败
if (!outputParentFile.exists() && !outputParentFile.mkdirs()) {
String errorMsg = new StringBuffer("创建文件输出路径失败:")
.append(outputParentFile.getAbsolutePath())
.toString();
logger.warn(errorMsg);
throw new RuntimeException(errorMsg);
}
// 创建输出文件对象
outputFile = new File(outputParentFile, "new.txt");
if (!outputFile.exists()) {
try {
outputFile.createNewFile();
} catch (IOException e) {
logger.warn("创建输出文件失败", e);
throw new RuntimeException("创建输出文件失败");
}
}
try (
// 创建字节输入流
FileInputStream fileInputStream = new FileInputStream(inputFile);
// 创建字节输入缓冲流
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
// 创建字节输出流
FileOutputStream fileOutputStream = new FileOutputStream(outputFile);
// 创建字节输出缓冲流
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
){
// 一次读取1024个字节,可以自己决定大小
byte[] bytes = new byte[1024];
while(bufferedInputStream.read(bytes) != -1) {
// 写入
bufferedOutputStream.write(bytes);
}
System.out.println("复制成功!");
// 后面不用写关闭输入输出流的代码,写在try()里面,编译时会自动生成关闭资源代码
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
上面用到的类都是 java.io包下的,字节方式输入输出可以用于其他类型文件,比如图片视频等。
运行结果:
用字符输入输出流实现
java
public static void main(String[] args) {
// 原文件(输入文件)
File inputFile = new File("D:/AAA/old.txt");
// 新文件输出路径
File outputParentFile = new File("D:/AAA");
// 新文件(输出文件)
File outputFile = null;
if (!inputFile.exists()) {
String errorMsg = new StringBuffer("原文件不存在:")
.append(inputFile.getAbsolutePath())
.toString();
logger.warn(errorMsg);
throw new RuntimeException(errorMsg);
}
// 输出路径不存在,且创建路径失败
if (!outputParentFile.exists() && !outputParentFile.mkdirs()) {
String errorMsg = new StringBuffer("创建文件输出路径失败:")
.append(outputParentFile.getAbsolutePath())
.toString();
logger.warn(errorMsg);
throw new RuntimeException(errorMsg);
}
// 创建输出文件对象
outputFile = new File(outputParentFile, "new.txt");
if (!outputFile.exists()) {
try {
outputFile.createNewFile();
} catch (IOException e) {
logger.warn("创建输出文件失败", e);
throw new RuntimeException("创建输出文件失败");
}
}
try (
// 创建字符输入流
FileReader fileReader = new FileReader(inputFile);
// 创建字符输入缓冲流
BufferedReader bufferedReader = new BufferedReader(fileReader);
// 创建字符输出流
FileWriter fileWriter = new FileWriter(outputFile);
// 创建字节输出缓冲流
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
){
// 当前行
String currentLine = null;
// StringUtils.isNotBlank 判断是否不为空
// bufferedReader.readLine() 一次读取一行文本
while(StringUtils.isNotBlank((currentLine = bufferedReader.readLine()))) {
// 写入当前行文本
bufferedWriter.write(currentLine);
// 新建一行
bufferedWriter.newLine();
}
// 还要写入其他内容可以继续 bufferedWriter.write("其他内容");
System.out.println("复制成功!");
// 后面不用写关闭输入输出流的代码,写在try()里面,编译时会自动生成关闭资源代码
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
NIO流读取文件写入
输入输出管道流(Channel)形式
正式使用的时候,记得加代码判断输入文件是否存在,输出文件目录是否存在,如果其中一个不存在会报错的,这里就不写了,代码参照上面IO流的。
java
public static void main(String[] args) {
try(
FileInputStream fileInputStream = new FileInputStream("D:/A.txt");
FileChannel inputChannel = fileInputStream.getChannel();
FileOutputStream fileOutputStream = new FileOutputStream("D:/A_COPY.txt");
FileChannel outputChannel = fileOutputStream.getChannel();
) {
long currentRead = 0;
// 理论上通过管道流的transferTo方法一次就可以交互输出完成,不需要while,但大文件可能会受限于操作系统,一次性没法输出完成,所以加一个while保险一点
while((currentRead += inputChannel.transferTo(currentRead, inputChannel.size(), outputChannel)) < inputChannel.size());
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
ByteBuffer字节缓冲区形式
正式使用的时候,记得加代码判断输入文件是否存在,输出文件目录是否存在,如果其中一个不存在会报错的,这里就不写了,代码参照上面IO流的。
java
public static void main(String[] args) {
try(
FileInputStream fileInputStream = new FileInputStream("D:/A.txt");
FileChannel inputChannel = fileInputStream.getChannel();
FileOutputStream fileOutputStream = new FileOutputStream("D:/A_COPY.txt");
FileChannel outputChannel = fileOutputStream.getChannel();
) {
// 通过ByteBuffer.allocate创建出一个指定容量的ByteBuffer,一旦指定容量就不能改变其大小。
// 当前指定一次读取写入20M,推荐不低于10M,一次性操作的字节越多,大文件读取写入就越快,当然性能消耗更大。
// 构造ByteBuffer有两个方法,ByteBuffer.allocate和ByteBuffer.allocateDirect,两个方法都是相同入参,含义却不同。
// ByteBuffer.allocate(capacity)分配的是非直接缓冲区,非直接缓冲区的操作会在Java堆内存中进行,数据的读写会通过Java堆来传递。、
// ByteBuffer.allocateDirect(capacity)分配的是直接缓冲区, 直接缓冲区的操作可以通过本地I/O传递,避免了在Java堆和本地堆之间的数据传输,可能在某些情况下提供更好的性能。
ByteBuffer byteBuffer = ByteBuffer.allocate(1024 * 1024 * 10 * 10);
int currentReadSize;
while((currentReadSize = inputChannel.read(byteBuffer)) > -1) {
// 将byteBuffer翻转,写模式和读模式转换
byteBuffer.flip();
outputChannel.write(byteBuffer);
// 清空byteBuffer,但只是下标重置,实际上内存并没有释放
byteBuffer.clear();
}
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
大文件推荐用NIO流操作,读取写入更快,几KB小文件都可以吧。至于IO流和NIO流区别,自己百度吧。
最后再说一个ByteArrayInputStream,ByteArrayOutputStream,有时候我们想读取一个文件的全部字节成一个byte[],然后再进行操作,比如转换成字符串啥的,但按照上面写出的方法,似乎都不满足, 这时候用ByteArray????Stream可以做到。
java
public static void main(String[] args) {
try(
FileInputStream fileInputStream = new FileInputStream("D:/A.txt");
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
) {
byte[] bytes = new byte[1024];
int currentReadSize;
while ((currentReadSize = bufferedInputStream.read(bytes)) != -1) {
byteArrayOutputStream.write(bytes, 0, currentReadSize);
}
byte[] byteArray = byteArrayOutputStream.toByteArray();
System.out.println(new String(byteArray));
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
码字不易,于你有利,勿忘点赞