目录
1.第一个简单的IO流
当程序需要读取数据源的数据时,就会通过 IO 流对象开启一个通向数据源的流,通过这个 IO 流对象的相关方法可以顺序读取数据源中的数据。
我们用程序创建一个a.txt的文本文档,在文本文档输入ABC三个字符并保存。
FileinputStream
package IO流_文件字节流;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
/*
* FileInputStream
* */
public class Test01 {
public static void main(String[] args) throws IOException {
// 创建文件
System.out.println(System.getProperty("user.dir"));
File file = new File("a.txt");
file.createNewFile();
// 创建字节输入流
FileInputStream fis = null;
try{
fis = new FileInputStream("d:/Project/2022.04.29 Day20/a.txt");
// 顺序读取文档中的内容,每读取到一个字符,转化为int类型的值返回回来
int num = fis.read();
int num1 = fis.read();
int num2 = fis.read();
int num3 = fis.read();
System.out.println(num);
System.out.println(num1);
System.out.println(num2);
System.out.println(num3);
}catch (Exception e){
e.printStackTrace();
}finally {
if (fis != null){
fis.close();
}
}
}
}
运行结果:
文本文档:
接下来我们对获取文档内容的方法做一个改进,让它不那么重复定义机械读取文件内容!
package IO流_文件字节流;
import java.io.FileInputStream;
/*
* 改进Test01
* */
public class Test01_01 {
public static void main(String[] args) {
// 字节流输入
FileInputStream fis = null;
try{
fis = new FileInputStream("D:/Project/2022.04.29 Day20/a.txt");
int temp = 0;
// 读取文件内容
while((temp = fis.read()) != -1){
System.out.println(temp);
}
}catch(Exception e){
e.printStackTrace();
}
finally {
if(fis != null){
try{
fis.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
}
因为我们正在调用read的方法的时候,一定会返回一个int类型的值,当顺序读取完最后一个字符之后,程序再往下读取就会返回给int一个-1的值。也就使我们判断程序终止的条件。
2.File类的使用
1.File类的简介
1.1File类的作用
File 类是Java 提供的针对磁盘中的文件或目录转换对象的包装类。一个 File 对象而可以代表一个文件或目录,File 对象可以实现获取文件和目录属性等功能,可以实现对文件和目录的创建,删除等功能。
1.2File类操作文件与目录的常用方法
creatNewFile() ------创建新文件
delete()------ 直接从磁盘中删除
exists()------查询磁盘中的文件是否存在
getAbsolutePath()------获取绝对路径
getPath() ------获取相对路径
getName() ------获取文件名,相当于调用了一次toString方法
isFile()------判断是否是文件
length() --------查看文件中的字节数
isHidden() ------查看是否是一个隐藏文件
1.3针对目录操作的方法
exists() ------目录是否存在
isDirectory() ------判断当前路径是否为目录
mkdir() -------创建一个目录,如果出现多级目录而中间目录缺失则创建失败
mkdirs() ------创建目录,如果中间目录缺失,直接创建缺失目录
getParentFile() ------获取当前目录的父级目录
list() ------返回一个字符串数组,包含目录中的文件和目录中的路径名
listFile() ------返回一个File数组,表示用此抽象路径名表示目录中的文件
2.File类的基本使用
package IO流_文件字节流;
import java.io.File;
import java.io.IOException;
import java.util.Date;
public class FileDemo {
public static void main(String[] args) throws IOException {
// 创建文件
File file = new File("d:/a.txt");
file.createNewFile(); //有一个boolean的返回值
System.out.println(file.createNewFile()); //因为已经创建好文件,所以返回false
System.out.println(file.exists()); //返回true
// 删除文件
System.out.println(file.delete()); //返回true 删除成功
// 重新创建文件
System.out.println(file.createNewFile());
// 获取文件名
System.out.println(file.getName());
// 判断是不是一个文件
System.out.println(file.isFile()); //返回一个、
// 判断是不是一个目录
System.out.println(file.isDirectory()); //返回false
// 判断是不是一个隐藏文件
System.out.println(file.isHidden()); //返回false
// 文件最后一次修改时间
System.out.println(new Date(file.lastModified()));
// File文件大小
System.out.println(file.length());
// File文件目录路径
System.out.println(file.getAbsolutePath());
System.out.println("删了ba:"+file.delete());
}
}
list双雄:
package IO流_文件字节流;
import java.io.File;
public class DirectoryDemo {
public static void main(String[] args) {
File file = new File("d:/A");
// 创建单级目录
System.out.println(file.mkdir());
// 创建多级目录
File file1 = new File("d:/B/C/D");
System.out.println(file1.mkdirs());
// 看看是不是目录
System.out.println(file.isDirectory());
// 获取父目录
System.out.println(file1.getParent());
File file2 = new File("d:/");
// 数组容量为file2的文件列表
String[] arr = file2.list();
// 获取文件列表,文件名
for(String str:arr){
System.out.println(str);
}
// 获取文件列表,文件绝对路径
File[] arr1 = file2.listFiles();
for(File str1:arr1){
System.out.println(str1);
}
}
}
3.常用流对象
1.文件字节流
FileInputStream 通过字节的方式读取文件,适合读取所有类型的文件(图像、视频、文本文件等)。Java 也提供了 FileReader 专门读取文本文件。
FileOutputStream 通过字节的方式写数据到文件中,适合所有类型的文件。Java 也提供了 FileWriter 专门写入文本文件。
1.1文件字节输入流
我们在D盘中创建文件夹A文件夹A下再创建一个A文件夹,放入一张File。png的图片
我们来读取图片信息返回到输出栏:
package IO流_文件字节流;
import java.io.FileInputStream;
public class FileInoutDemo01 {
public static void main(String[] args) {
FileInputStream fileInputStream = null;
try{
fileInputStream = new FileInputStream("d:/A/A/File.png");
int temp = 0;
// int 返回大小在0~255之间
while((temp = fileInputStream.read()) != -1){
System.out.println(temp);
}
}catch (Exception e){
e.printStackTrace();
}finally {
try{
if (fileInputStream != null){
fileInputStream.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
运行结果:
1.2文件字节输出流
我们将上述图片信息读入程序并写出去(模拟复制图片的过程),为了方便观察,我们就写进同一个文件夹下面。
package IO流_文件字节流;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class FileInputDemo {
public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null;
try{
// 读取文件
fis = new FileInputStream("d:/A/A/File.png");
// 创建文件字节输出流对象
fos = new FileOutputStream("d:/A/A/aa.png");
int temp = 0;
// 读取文件的字节流返回的int值趋于(0~255)之间
while((temp = fis.read()) != -1){
// 复制过程
fos.write(temp);
}
// 将数据从内存中写入到磁盘中
fos.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
if(fis != null){
try{
fis.close();
}catch (Exception e){
e.printStackTrace();
}
}
if(fos != null){
try{
fos.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
}
运行结果:
1.3通过缓冲区提高读写效率
1.3.1方式一
通过创建一个指定长度的字节数组作为缓冲区,以此来提高 IO 流的读写效率。该方式适用于读取较大图片时的缓冲区定义。注意:缓冲区的长度一定是 2 的整数幂。一般情况下1024较为合适。
package IO流_文件字节流;
import java.io.*;
/*
* 通过缓冲区提高读写效率
* */
public class FileStreamBufferDemo {
public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null;
try{
// 创建文件字节输入流
fis = new FileInputStream("d:/B/File.png");
// 创建文件字节输出流
fos = new FileOutputStream("d:/B/copy.png");
// 定义一个byte类型的数组
byte[] buffer = new byte[1024];
// 读取的文件返回一个int类型大小的字符
int temp;/*
// 方式一:
// 计算运行时间:运行结果系统所需时间为:1
long time = System.currentTimeMillis();
while((temp = fis.read(buffer)) != -1){
fos.write(temp);
}
long time1 = System.currentTimeMillis();
System.out.println("系统运行所需时间为:"+(time1-time));*/
// 普通方式
// 计算运行时间(运行时间为:473)
long time = System.currentTimeMillis();
while((temp = fis.read()) != -1){
fos.write(temp);
}
long time1 = System.currentTimeMillis();
System.out.println("系统运行所需时间为:"+(time1-time));
}catch(Exception e){
e.printStackTrace();
}finally {
try{
if(fis != null){
fis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
1.3.2方式二
通过创建一个字节数组作为缓冲区,数组长度是通过输入流对象的 available()返回当前文件的预估长度来定义的。在读写文件时,是在一次读写操作中完成文件读写操作的。注意: 如果文件过大,那么对内存的占用也是比较大的。所以大文件不建议使用该方法。
package IO流_文件字节流;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class InputStreamAvaliable {
public static void main(String[] args) {
FileInputStream fileInputStream = null;
FileOutputStream fileOutputStream = null;
try{
fileInputStream = new FileInputStream("d:/A/A/File.png");
fileOutputStream = new FileOutputStream("d:/A/A/AvaliableCopy.png");
int temp = 0;
while ((temp = fileInputStream.read()) != -1){
fileOutputStream.write(temp);
}
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if(fileInputStream != null){
fileInputStream.close();
}
if (fileOutputStream != null){
fileOutputStream.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
运行结果:
1.4通过字节缓冲流提高读写效率
Java 缓冲流本身并不具有 IO 流的读取与写入功能,只是在别的流(节点流或其他处理流)上加上缓冲功能提高效率,就像是把别的流包装起来一样,因此缓冲流是一种处理流(包 装流)。
当对文件或者其他数据源进行频繁的读写操作时,效率比较低,这时如果使用缓冲流就 能够更高效的读写信息。因为缓冲流是先将数据缓存起来,然后当缓存区存满后或者手动刷 新时再一次性的读取到程序或写入目的地。
因此,缓冲流还是很重要的,我们在 IO 操作时记得加上缓冲流来提升性能。
BufferedInputStream 和 BufferedOutputStream 这两个流是缓冲字节流,通过内部缓存数组来提高操作流的效率。
package IO流_文件字节流;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class FileStreamBufferDemo_02 {
public static void main(String[] args) {
// 定义字节输入流
FileInputStream fis =null;
// 定义输出流
FileOutputStream fos = null;
// 字节缓冲流
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try{
fis = new FileInputStream("d:/A/File.png");
bis = new BufferedInputStream(fis);
fos = new FileOutputStream("d:/A/ABC.png");
bos = new BufferedOutputStream(fos);
//计算时间(运行时间为7)
long timeStart = System.currentTimeMillis();
int temp = 0;
while((temp = bis.read()) != -1){
bos.write(temp);
}
bos.flush();
long timeEnd = System.currentTimeMillis();
System.out.println("运行时间:"+(timeEnd-timeStart));
}catch (Exception e ){
}finally {
try{
if (fis != null){
fis.close();
}
if (bis != null){
bis.close();
}
if(fos != null){
fos.close();
}
if (bos != null){
bos.close();
}
}catch (Exception e){
}
}
}
}
1.5定义文件拷贝工具类
package IO流_文件字节流;
import java.io.*;
public class CopyFileTest {
public static void main(String[] args) {
copyFile("d:/A/File.png","d:/A/AAA.png");
}
static void copyFile(String src,String des){
FileInputStream fis = null;
BufferedInputStream bis = null;
FileOutputStream fos = null;
BufferedOutputStream bos = null;
try{
bis = new BufferedInputStream(new FileInputStream(src));
bos = new BufferedOutputStream(new FileOutputStream(des));
int temp = 0;
while((temp = bis.read()) != -1){
bos.write(temp);
}
bos.flush();
}catch (Exception e){
e.printStackTrace();
}
finally {
try{
if(fis != null){
fis.close();
}
if (fos != null){
fos.close();
}
if (bis != null){
bis.close();
}
if (bos != null){
bos.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
2.文件字符流
前面介绍的文件字节流可以处理所有的文件,如果我们处理的是文本文件,也可以使用 文件字符流,它以字符为单位进行操作。
2.1文件字符输入流
尽管我们是字符输出对象,但在read()方法读取数据的时候还是会将我们读取到的东西转化为int类型,所以需要强转为char类型
package IO流_文件字符流;
import java.io.FileReader;
public class FileReaderDemo {
public static void main(String[] args) {
// 创建文件字符流
FileReader fileReader = null;
try{
// 创建文件字符输入流对象
fileReader = new FileReader("d:/A/A/a.txt");
int temp = 0;
while((temp = fileReader.read()) != -1){
// 将int类型强转为char类型
System.out.println((char) temp);
}
}catch (Exception e){
}
finally {
try{
if (fileReader != null){
fileReader.close();
}
}catch (Exception e){
}
}
}
}
2.2文件字符输出流
package IO流_文件字符流;
import java.io.FileWriter;
public class FileWriterDemo {
public static void main(String[] args) {
FileWriter fileWriter = null;
FileWriter fileWriter2 = null;
try{
// 默认覆盖源文件,需要增加参数来作追加文本处理
fileWriter = new FileWriter("d:/A/B.txt");
// 当发现文件当中没有该文档,会在该地址自行创建!
fileWriter.write("你好,字符输出流!");
// \n\r 为回车换行
fileWriter.write("你是一个方便的文件控制方法!\n\r");
fileWriter.write("你会自行刷新吗!");
fileWriter.flush();
fileWriter2 = new FileWriter("d:/A/B.txt");
fileWriter2.write("我是追加的字符段!\n\r");
fileWriter2.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
try{
if (fileWriter != null){
fileWriter.close();
}
}catch (Exception e ){
e.printStackTrace();
}
}
}
}
2.3使用文件字符流实现文本文件的拷贝处理。
package IO流_文件字符流;
import java.io.FileReader;
import java.io.FileWriter;
/*
* 缓冲读取机制
* */
public class FileCopyDemo {
public static void main(String[] args) {
FileWriter fileWriter =null;
FileReader fileReader = null;
try{
fileReader = new FileReader("d:/A/A.txt");
fileWriter = new FileWriter("d:/A/B.txt");
int temp = 0;
char[] buffer = new char[1024];
while((temp = fileReader.read(buffer)) != -1){
// 从数组buffer的起始位置开始写(0),写temp个
fileWriter.write(buffer,0,temp);
}
fileWriter.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
try{
if (fileReader != null){
fileReader.close();
}
if (fileWriter != null){
fileWriter.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
3.字符缓冲流
3.1字符输入缓冲流
BufferedReader 是针对字符输入流的缓冲流对象,提供了更方便的按行读取的方法:
readLine(); 在使用字符流读取文本文件时,我们可以使用该方法以行为单位进行读取。
package IO流_文件字符流;
import java.io.BufferedReader;
import java.io.FileReader;
/*
* 熟悉ReaderLine用法
* */
public class BufferedReaderTest {
public static void main(String[] args) {
FileReader fileReader = null;
BufferedReader bufferedReader = null;
try{
fileReader = new FileReader("d:/A/A.txt");
bufferedReader = new BufferedReader(fileReader);
String temp =" ";
while((temp = bufferedReader.readLine()) != null){
System.out.println(temp);
}
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if (fileReader != null){
fileReader.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
3.2字符输出缓冲流
BufferedWriter 是针对字符输出流的缓冲流对象, 在字符输出缓冲流中可以使用
newLine();方法实现换行处理。
package IO流_文件字符流;
import java.io.BufferedWriter;
import java.io.FileWriter;
public class BufferedWriterTest {
public static void main(String[] args) {
FileWriter fileWriter = null;
BufferedWriter bufferedWriter= null;
try{
fileWriter = new FileWriter("d:/A/c.txt");
bufferedWriter = new BufferedWriter(fileWriter);
bufferedWriter.write("你好Java!");
bufferedWriter.write("你好BufferedWriter!");
// 换行处理
bufferedWriter.newLine();
bufferedWriter.write("谢谢你们方便了我们!");
// 刷新
bufferedWriter.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
try{
if (fileWriter != null){
fileWriter.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
3.3通过字符缓冲流实现文本文件的拷贝
package IO流_文件字符流;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
/*
* 基于字符缓冲流实现文件拷贝
* */
public class
FileCopyDemo_03 {
public static void main(String[] args) {
copyFile("d:/A/c.txt","d:/A/d.txt");
}
static void copyFile(String src,String des){
FileWriter fileWriter = null;
FileReader fileReader = null;
BufferedWriter bufferedWriter = null;
BufferedReader bufferedReader = null;
try{
fileReader = new FileReader(src);
fileWriter = new FileWriter(des);
bufferedReader = new BufferedReader(fileReader);
bufferedWriter = new BufferedWriter(fileWriter);
String temp = " ";
while ((temp = bufferedReader.readLine()) != null){
bufferedWriter.write(temp);
bufferedWriter.newLine();
}
bufferedWriter.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
try{
if (fileReader == null){
fileReader.close();
}
if (fileWriter == null){
fileWriter.close();
}
if(bufferedReader ==null){
bufferedReader.close();
}
if (bufferedReader == null){
bufferedReader.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
3.4通过字符缓冲流为文件中的内容添加行号
package IO流_文件字符流;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
public class LineNumberDemo {
public static void main(String[] args) {
BufferedReader bufferedReader = null;
BufferedWriter bufferedWriter = null;
try{
bufferedReader = new BufferedReader(new FileReader("d:/A/c.txt"));
bufferedWriter = new BufferedWriter(new FileWriter("d:/A/D.txt"));
String temp = " ";
int i = 1;
while((temp = bufferedReader.readLine()) != null){
bufferedWriter.write(i+"、"+temp);
bufferedWriter.newLine();
i++;
}
}catch (Exception e){
e.printStackTrace();
}finally{
try{
if (bufferedReader != null){
bufferedReader.close();
}
if(bufferedWriter != null){
bufferedWriter.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
4.转换流
InputStreamReader/OutputStreamWriter 用来实现将字节流转化成字符流。比如,如下场景:System.in 是字节流对象,代表键盘的输入,如果我们想按行接收用户的输入时,就必须用到缓冲字符流 BufferedReader 特有的方法 readLine(), 但是经过观察会发现在创建BufferedReader 的构造方法的参数必须是一个 Reader 对象, 这时候我们的转换流InputStreamReader 就派上用场了。而 System.out 也是字节流对象,代表输出到显示器,按行读取用户的输入后,并且要将读取的一行字符串直接显示到控制台,就需要用到字符流的 write(String str)方法,所以我们要使用 OutputStreamWriter 将字节流转化为字符流。
4.1通过转换流实现字节输入屏幕输出
package IO流_文件字符流;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
public class ConvertStream {
public static void main(String[] args) {
BufferedWriter bufferedWriter = null;
BufferedReader bufferedReader = null;
try{
while(true){
bufferedReader = new BufferedReader(new InputStreamReader(System.in));
String input = bufferedReader.readLine();
bufferedWriter = new BufferedWriter(new OutputStreamWriter(System.out));
bufferedWriter.write("您输入的字符串是:"+input);
bufferedWriter.newLine();
bufferedReader.readLine();
bufferedWriter.flush();
if ("exit".equals(input)){
break;
}
}
}catch (Exception e){
}finally {
try{
if (bufferedReader != null){
bufferedReader.close();
}
if (bufferedWriter != null){
bufferedWriter.close();
}
} catch (Exception e){
e.printStackTrace();
}
}
}
}
4.2通过字节流读取文本文件并添加行号
package IO流_文件字符流;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
public class LineNumberDemo_02 {
public static void main(String[] args) {
BufferedReader bufferedReader = null;
//
PrintWriter printWriter = null;
try{
bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream("d:/A/c.txt")));
printWriter = new PrintWriter("d:/A/F.txt");
String temp = "";
int i =1;
while((temp = bufferedReader.readLine()) != null){
printWriter.println("i"+temp);
i++;
}
printWriter.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
try{
if(bufferedReader != null){
bufferedReader.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
5.字符输出流
在 Java 的 IO 流中专门提供了用于字符输出的流对象 PrintWriter。该对象具有自动行刷新缓冲字符输出流,特点是可以按行写出字符串,并且可通过 println();方法实现自动换行。
package IO流_文件字符流;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
public class LineNumberDemo_02 {
public static void main(String[] args) {
BufferedReader bufferedReader = null;
//
PrintWriter printWriter = null;
try{
bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream("d:/A/c.txt")));
printWriter = new PrintWriter("d:/A/F.txt");
String temp = "";
int i =1;
while((temp = bufferedReader.readLine()) != null){
printWriter.println("i"+temp);
i++;
}
printWriter.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
try{
if(bufferedReader != null){
bufferedReader.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
6.字节数组流
ByteArrayInputStream 和 ByteArrayOutputStream 经常用在需要流和数组之间转化的情况!
6.1字节数组输入流
说白了,FileInputStream 是把文件当做数据源。ByteArrayInputStream 则是把内存中的” 字节数组对象”当做数据源。
package IO流_文件字符流;
import java.io.ByteArrayInputStream;
public class ByteArrayInputDemo {
public static void main(String[] args) {
byte[] arr = "abcdefg".getBytes();
ByteArrayInputStream byteArrayInputStream = null;
StringBuilder sb = new StringBuilder();
try{
byteArrayInputStream = new ByteArrayInputStream(arr);
int temp = 0;
while((temp = byteArrayInputStream.read()) != -1){
sb.append((char)temp);
}
System.out.println(sb.reverse().toString());
}finally {
try{
if(byteArrayInputStream != null){
byteArrayInputStream.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
6.2字节数组输出流
ByteArrayOutputStream 流对象是将流中的数据写入到字节数组中。
package IO流_文件字符流;
import java.io.ByteArrayOutputStream;
public class ByteArrayOutputDemo {
public static void main(String[] args) {
ByteArrayOutputStream byteArrayOutputStream = null;
try{
StringBuilder sb = new StringBuilder();
byteArrayOutputStream = new ByteArrayOutputStream();
byteArrayOutputStream.write('A');
byteArrayOutputStream.write('B');
byteArrayOutputStream.write('C');
byte[] arr = byteArrayOutputStream.toByteArray();
for (byte temp:arr){
sb.append((char) temp);
System.out.println((char)temp);
}
System.out.println(sb.toString());
}finally {
try{
if (byteArrayOutputStream != null){
byteArrayOutputStream.close();
}
}catch (Exception e){
}
}
}
}
7.数据流
数据流将“基本数据类型与字符串类型”作为数据源,从而允许程序以与机器无关的方式 从底层输入输出流中操作 Java 基本数据类型与字符串类型。
DataInputStream 和DataOutputStream 提供了可以存取与机器无关的所有 Java 基础类型数据(如:int、double、String 等)的方法。
7.1数据输入流
package IO流_文件字符流;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.FileInputStream;
public class DataInputDemo {
public static void main(String[] args) {
DataInputStream dataInputStream = null;
try{
dataInputStream = new DataInputStream(new BufferedInputStream(new FileInputStream("d:/A/E.txt")));
System.out.println("int:"+dataInputStream.readInt());
System.out.println("boolean:"+dataInputStream.readBoolean());
System.out.println("char:"+dataInputStream.readChar());
System.out.println("double:"+dataInputStream.readDouble());
System.out.println("String:"+dataInputStream.readUTF());
}catch (Exception e){
e.printStackTrace();
}finally {
try{
if (dataInputStream != null){
dataInputStream.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
7.2 数据输出流
package IO流_文件字符流;
import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.FileOutputStream;
public class DataOutputDemo {
public static void main(String[] args) {
DataOutputStream dataOutputStream= null;
try{
dataOutputStream = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("d:/A/E.txt")));
dataOutputStream.writeInt(1);
dataOutputStream.writeBoolean(false);
dataOutputStream.writeChar('c');
dataOutputStream.writeDouble(1.3);
dataOutputStream.writeUTF("你好,Java!");
dataOutputStream.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
try{
if(dataOutputStream != null){
dataOutputStream.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
8.对象流
对象的本质是用来组织和存储数据的,对象本身也是数据。那么,能不能将对象存储到 硬盘上的文件中呢?能不能将对象通过网络传输到另一个电脑呢?我们可以通过序列化和 反序列化来实现这些需求。
8.1Java对象的序列化和反序列化
8.1.1序列化和反序列化是什么
当两个进程远程通信时,彼此可以发送各种类型的数据。 无论是何种类型的数据,都会以二进制序列的形式在网络上传送。比如,我们可以通过 http 协议发送字符串信息;我们也可以在网络上直接发送 Java 对象。发送方需要把这个 Java 对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为 Java 对象才能正常读取。
把 Java 对象转换为字节序列的过程称为对象的序列化。把字节序列恢复为 Java 对象的过程称为对象的反序列化。
对象序列化的作用有如下两种:
- 持久化: 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中。
2.网络通信:在网络上传送对象的字节序列。比如:服务器之间的数据通信、对象传 递。
8.1.2序列化设计的类和接口
ObjectOutputStream 代表对象输出流,它的 writeObject(Object obj)方法可对参数指定的obj 对象进行序列化,把得到的字节序列写到一个目标输出流中。
ObjectInputStream 代表对象输入流,它的 readObject()方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。
只有实现了 Serializable 接口的类的对象才能被序列化。Serializable 接口是一个空接口, 只起到标记作用。
8.2操作基本数据类型
我们前边学到的数据流只能实现对基本数据类型和字符串类型的读写,并不能对 Java 对象进行读写操作(字符串除外),但是在对象流中除了能实现对基本数据类型进行读写操 作以外,还可以对 Java 对象进行读写操作。
8.2.1写出基本数据类型数据
package 对象流;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
public class ObjectOutputStreamBasicType {
public static void main(String[] args) {
ObjectOutputStream oos = null;
try{
oos = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream("d:/A/G.txt")));
oos.writeInt(15);
oos.writeDouble(15.0);
oos.writeBoolean(false);
oos.writeChar('C');
oos.writeUTF("你好,Java!");
}catch (Exception e){
}finally {
try {
if(oos != null){
oos.close();
}
}catch (Exception e){
}
}
}
}
8.2.2读取基本类型数据
package 对象流;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class ObjectInputStreamBasicType {
public static void main(String[] args) {
ObjectInputStream ois = null;
try{
ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream("d:/A/G.txt")));
System.out.println(ois.readInt());
System.out.println(ois.readDouble());
System.out.println(ois.readBoolean());
System.out.println(ois.readChar());
System.out.println(ois.readUTF());
}catch (Exception e){
e.printStackTrace();
}finally {
try{
if(ois != null){
ois.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
8.3操作对象
8.3.1将对象序列化到文件
ObjectOutputStream 可以将一个内存中的 Java 对象通过序列化的方式写入到磁盘的文件中。被序列化的对象必须要实现 Serializable 序列化接口,否则会抛出异常。
8.3.1.1创建对象
package 对象流;
import java.io.Serializable;
public class User implements Serializable {
private int userId;
public User() {
}
private String username;
private String userAge;
public User(int userId, String username, String userAge) {
this.userId = userId;
this.username = username;
this.userAge = userAge;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getUserAge() {
return userAge;
}
public void setUserAge(String userAge) {
this.userAge = userAge;
}
}
8.3.1.2序列化对象
package 对象流;
import com.sun.corba.se.impl.orbutil.ObjectWriter;
/*
* 将对象序列化到文件中
* */
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
public class ObjectOutputStreamObjectDemo {
public static void main(String[] args) {
ObjectOutputStream objectOutputStream = null;
try{
objectOutputStream = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream("d:/A/A/b.txt")));
User user = new User(20220501,"张三","18");
objectOutputStream.writeObject(user);
objectOutputStream.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
try{
if (objectOutputStream != null){
objectOutputStream.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
8.3.2将对象反序列化到内存中
package 对象流;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
// 反序列化user
public class ObjectInputObjectTypeDemo {
public static void main(String[] args) {
ObjectInputStream objectInputStream = null;
try{
objectInputStream = new ObjectInputStream(new BufferedInputStream(new FileInputStream("d:/A/A/b.txt")));
User user = (User)objectInputStream.readObject();
System.out.println(user.getUserId()+"\t"+user.getUsername()+user.getUserAge()+"\t");
}catch (Exception e){
e.printStackTrace();
}finally {
try{
if (objectInputStream != null){
objectInputStream.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
9.随机访问流
RandomAccessFile 可以实现两个作用:
- 实现对一个文件做读和写的操作。
- 可以访问文件的任意位置。不像其他流只能按照先后顺序读取。
在开发某些客户端软件时,经常用到这个功能强大的可以”任意操作文件内容”的类。比 如,软件的使用次数和使用日期,可以通过本类访问文件中保存次数和日期的地方进行比对 和修改。 Java 很少开发客户端软件,所以在 Java 开发中这个类用的相对较少。
学习这个流我们需掌握三个核心方法:
RandomAccessFile(String name, String mode) name 用来确定文件; mode 取r(读)或 rw(可读写),通过 mode 可以确定流对文件的访问权限。seek(long a) 用来定位流对象读写文件的位置,a 确定读写位置距离文件开头的字节个数。getFilePointer() 获得流的当前读写位置。
package 随机访问流;
import java.io.RandomAccessFile;
public class RandomAccessFileDemo {
public static void main(String[] args) {
RandomAccessFile randomAccessFile = null;
try{
randomAccessFile = new RandomAccessFile("d:/A/F.txt","rw");
// 将int数组写入文件中
int[] arr = new int[]{10,20,30,40,50,60,70,80,90,100};
for (int i = 0;i<10;i++){
randomAccessFile.writeInt(arr[i]);
}
// 一个int四个字节
randomAccessFile.seek(8);
System.out.println(randomAccessFile.readInt());
// 读取文件内容
randomAccessFile.seek(0);
for(int i = 0;i<10;i++){
System.out.print(randomAccessFile.readInt()+"\t");
}
System.out.println("");
// 隔一取一,读取文件内容
System.out.println("");
for(int i = 0;i<10;i+=2){
randomAccessFile.seek(i*4);
System.out.print(randomAccessFile.readInt()+"\t");
}
System.out.println("");
// 改变文件的值
randomAccessFile.seek(8);
randomAccessFile.writeInt(99);
randomAccessFile.seek(0);
for(int i = 0;i<10;i++){
System.out.print(randomAccessFile.readInt()+"\t");
}
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if(randomAccessFile != null){
randomAccessFile.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
10.File在IO中的作用
当以文件作为数据源或目标时,除了可以使用字符串作为文件以及位置的指定以外,我 们也可以使用 File 类指定。
package File文件;
import java.io.*;
public class FileIODemo {
public static void main(String[] args) {
BufferedReader br = null;
BufferedWriter bw = null;
try{
br = new BufferedReader(new FileReader(new File("d:/A/c.txt")));
bw = new BufferedWriter(new FileWriter(new File("d:/A/G.txt")));
String temp = "";
int i = 0;
while((temp = br.readLine()) != null){
bw.write(i+"、"+temp);
bw.newLine();
i++;
}
}catch (Exception e){
e.printStackTrace();
}finally {
try{
if(br != null){
br.close();
}
if (bw != null){
bw.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
Apache IO 包
JDK 中提供的文件操作相关的类,但是功能都非常基础,进行复杂操作时需要做大量编程工作。实际开发中,往往需要你自己动手编写相关的代码,尤其在遍历目录文件时,经常 用到递归,非常繁琐。 Apache-commons 工具包中提供了 IOUtils/FileUtils,可以让我们非常方便的对文件和目录进行操作。 本文就是让大家对 IOUtils/FileUtils 类有一个全面的认识, 便于大家以后开发与文件和目录相关的功能。
Apache IOUtils 和 FileUtils 类库为我们提供了更加简单、功能更加强大的文件操作和 IO
流操作功能。非常值得大家学习和使用。
下载地址
https://commons.apache.org/proper/commons-io/download_io.cgi
- FileUtils 的使用
FileUtils 类中常用方法:
打开 FileUtils 的 api 文档,我们抽出一些工作中比较常用的方法,进行总结和讲解。总结如下:
cleanDirectory:清空目录,但不删除目录。
contentEquals:比较两个文件的内容是否相同。
copyDirectory:将一个目录内容拷贝到另一个目录。可以通过 FileFilter 过滤需要拷贝的文件。
copyFile:将一个文件拷贝到一个新的地址。
copyFileToDirectory:将一个文件拷贝到某个目录下。
copyInputStreamToFile:将一个输入流中的内容拷贝到某个文件。
deleteDirectory:删除目录。
deleteQuietly:删除文件。
listFiles:列出指定目录下的所有文件。
openInputSteam:打开指定文件的输入流。
readFileToString:将文件内容作为字符串返回。
readLines:将文件内容按行返回到一个字符串数组中。
size:返回文件或目录的大小。
write:将字符串内容直接写到文件中。
writeByteArrayToFile:将字节数组内容写到文件中。
writeLines:将容器中的元素的 toString 方法返回的内容依次写入文件中。
writeStringToFile:将字符串内容写到文件中
FileUtils使用一
package ApacheIO;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.FileInputStream;
/*
* 读文件
* */
public class FileUtilsDemo1 {
public static void main(String[] args) throws Exception{
String content = FileUtils.readFileToString(new File("d:/A/c.txt"),"UTF-8");
System.out.println(content);
}
}
FileUtils使用二
package ApacheIO;
import com.sun.org.apache.xml.internal.serialize.XHTMLSerializer;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.FileFilter;
public class FileUtilsDemo2 {
public static void main(String[] args) throws Exception{
FileUtils.copyDirectory(new File("d:/B/C/D"), new File("d:/D"), new FileFilter() {
// 文件拷贝时的过滤条件
@Override
public boolean accept(File pathname) {
if (pathname.isDirectory() || pathname.getName().endsWith("html")){
return true;
}
return false;
}
});
}
}
IOUtils 的使用
打开 IOUtils 的 api 文档,我们发现它的方法大部分都是重载的。所以,我们理解它的方法并不是难事。因此,对于方法的用法总结如下:
buffer 方法:将传入的流进行包装,变成缓冲流。并可以通过参数指定缓冲大小。
closeQueitly 方法:关闭流。
contentEquals 方法:比较两个流中的内容是否一致。
copy 方法:将输入流中的内容拷贝到输出流中,并可以指定字符编码。
copyLarge 方法:将输入流中的内容拷贝到输出流中,适合大于 2G 内容的拷贝。
lineIterator 方法:返回可以迭代每一行内容的迭代器。
read 方法:将输入流中的部分内容读入到字节数组中。
readFully 方法:将输入流中的所有内容读入到字节数组中。
readLine 方法:读入输入流内容中的一行。
toBufferedInputStream,toBufferedReader:将输入转为带缓存的输入流。
toByteArray,toCharArray:将输入流的内容转为字节数组、字符数组。
toString:将输入流或数组中的内容转化为字符串。
write 方法:向流里面写入内容。
writeLine 方法:向流里面写入一行内容。
package ApacheIO;
import org.apache.commons.io.IOUtils;
import java.io.FileInputStream;
public class IOUtilsDemo {
public static void main(String[] args) throws Exception{
String content = IOUtils.toString(new FileInputStream("d:/A/c.txt"),"utf-8");
System.out.println(content);
}
}
本章总结
按流的方向分类:
-
- 输入流:数据源到程序(InputStream、Reader 读进来)。
- 输出流:程序到目的地(OutPutStream、Writer 写出去)。
- 按流的处理数据单元分类:
- 字节流:按照字节读取数据(InputStream、OutputStream)。
- 字符流:按照字符读取数据(Reader、Writer)。
- 按流的功能分类:
- 节点流:可以直接从数据源或目的地读写数据。
- 处理流:不直接连接到数据源或目的地,是处理流的流。通过对其他流的处理 提高程序的性能。
- IO 的四个基本抽象类:InputStream、OutputStream、Reader、Writer
- InputStream 的实现类:
- FileInputStream
- ByteArrayInutStream
- BufferedInputStream
- DataInputStream
- ObjectInputStream
- OutputStream 的实现类:
- FileOutputStream
- ByteArrayOutputStream
- BufferedOutputStream
- DataOutputStream
- ObjectOutputStream
- PrintStream
- Reader 的实现类
- FileReader
- BufferedReader
- InputStreamReader
- Writer 的实现类
- FileWriter
- BufferedWriter
- OutputStreamWriter
- 把 Java 对象转换为字节序列的过程称为对象的序列化。
- 把字节序列恢复为 Java 对象的过程称为对象的反序列化。
累死我了!!!!