Java基础八:IO

File类

  • File能新建、删除、重命名文件和目录,但File不能访问文件内容本身。如果需要访问文件内容本身,则需要使用IO流
  • 想要在Java程序中表示一个真实存在的文件或目录,那么必须有一个File对象,但是Java程序中的一个File对象,可能没有一个真实存在的文件或目录
  • File对象可以作为参数传递给流的构造器

常用构造器

public File(String pathname):以pathname为路径创建File对象,可以是绝对路径或者相对路径
public File(String parent, String child):以parent为父路径,child为子路径创建File对象(例:File file3 = new File("D:\\workspace_idea1","JavaSenior");,在parent路径下创建了一个child)
public File(File parent, String child):在父File的路径下创建一个child

  • Java支持跨平台运行,所以路径格式要格外注意。为了解决这个隐患,File类提供了一个常量public static final String separator,可根据操作系统,动态匹配对应的格式。如下:
File file1 = new File("d:\\coding\\info.txt")
File file2 = new File("d:" + File.separator + "coding" + File.separator + "info.txt");
常用方法
方法功能
String getAbsolutePath()获取绝对路径
String getPath()获取构造参数输入的路径
String getName()获取名称
String getParent()获取上层文件目录路径,若无返回null
long length()获取文件长度(即字节数)。不能获取目录的长度
long lastModified()获取最后一次修改时间,毫秒值
String[] list()获取指定目录下所有文件或者文件目录的名称数组
File[] listFiles()获取指定目录下所有文件或者文件目录的File数组
boolean renameTo(File dest)把文件重命名为指定的文件路径
boolean isDirectory()判断是否是文件目录
boolean isFile()判断是否是文件
boolean exists()判断是否存在
boolean canRead()判断是否可读
boolean canWrite()判断是否可写
boolean isHidden()判断是否隐藏
boolean createNewFile()创建文件,若已存在,则不创建并返回false
boolean mkdir()创建文件目录,若已存在就不创建;若上层目录不存在,则不创建
boolean mkdirs()创建文件目录,若上层文件目录不存在,则一并创建
boolean delete()删除文件或文件夹

如果创建文件或文件夹没有写盘符路径,那么默认在项目路径下
Java中的删除不走回收站
要删除一个文件夹,请注意该文件夹内不能包含文件或子文件夹


IO流

java.io包下提供了各种“流”类和接口,用于获取不同种类的数据,处理设备之间的数据传输,并通过标准的方法输入或输出数据

流的分类
  • 按数据单位不同分为:字节流(8 bit),字符流(16 bit)
  • 按数据的流向不同分为:输入流,输出流
  • 按流的作用不同分为:节点流(数据、文件的流形式本身),处理流(处理节点流或处理流的流,一个节点流可以有多层处理流)
抽象基类字节流字符流
输入流InputStreamReader
输出流OutputStreamWriter
  1. Java的IO流共涉及40多个类,实际上非常规则,都是从上面4个抽象基类派生的
  2. 派生出来的子类名称都是以其父类名作为后缀

在这里插入图片描述
在这里插入图片描述

  • 节点流:直接从数据源或目的地读写数据
  • 处理流:不直接连接到数据源或目的地,而是“包裹”在已存在的流(节点流或处理流)之上,通过对数据的处理为程序提供更为强大的读写能力
流的体系结构
抽象基类节点流(文件流)缓冲流(处理流的一种)
InputStreamFileInputStreamBufferInputStream
OutputStreamFileOutputStreamBufferInputStream
ReaderFileReaderBufferInputStream
WriterFileWriterBufferInputStream
数据的读入
//1.实例化File类对象,指明要操作的文件
File file = new File("hello.txt");
//2.提供具体的流
FileReader fr = new FileReader(file);//往往会有异常需要处理。一般都用try-catch处理

//3.数据的读入
int data = fr.read();//read()返回读入的一个字符,如果达到文件末尾,返回-1
while(data != -1){
	System.out.println((char)data);
	data = fr.read();
}

//4.流的关闭操作
//因为垃圾回收机制只回收JVM堆内存里的对象空间,对于其他物理连接,比如数据库连接、IO流、Socket连接无能为力,所以这些连接用完后要手动关闭,否则会导致内存泄露
fr.close();//要用finally包一下

异常的处理:为了保证流资源一定可以执行关闭操作,需要使用try-catch-finally

上面的3步可以改进成:

//read(char[] cbuf)返回每次读入cbuf数组中的字符个数。如果达到文件末尾,返回-1
char[] cbuf = new char[5];
int len;
while((len = fr.read(sbuf)) != -1){
	for(int i = 0; i < len; i++){
		System.out.print(cbuf[i]);
	}
	//这里也可以替换成
	//String str = new String(cbuf, 0, len);
	//System.out.print(str);
};
数据的写出
//1.提供File类的对象,指明写出到的文件
File file = new File("hello.txt");
//2.提供FileWriter的对象,用于数据的写出
FileWriter fw = new FileWriter(file);
//3.写出的操作
fw.write("I have a dream!");
//4.流资源的关闭
fw.close();

说明:

  1. 输出操作对应的File若不存在,会自动创建此文件
  2. 如果存在,且流使用的构造器是FileWriter(file, false)/FileWriter(file),则对原有文件覆盖
    若流构造器是FileWriter(file, true),不会覆盖原文件,会在其后追加内容
数据的读入和写出
//1.创建File类的对象,指明读入和写出的文件
File srcFile = new File("hello.txt");
File destFile = new File("hey.txt");
//2.创建输入流和输出流的对象
FileReader fr = new FileReader(srcFile);
FileWriter fw = new FileWriter(destFile);
//3.数据的读入和写出操作
char[] cbuf = new char[5];
int len;//记录每次读入到cbuf数组中的字符的个数
while((len = fr.read(cbuf)) != -1){
	fw.write(cbuf, o, len);
}
//4.关闭流资源
fw.close();
fr.close();

不能使用字符流处理字节文件

  1. 对于文本文件,一般使用字符流处理
  2. 对于非文本文件,只能使用字节流处理

若用字节流处理字符流,如果只是复制,是不会出现乱码的,因为它只是在“搬运”;但如果在控制台进行打印,可能会出现乱码,因为打印输出牵扯到字符编码的问题。

//1.造文件
File file = new File("hello.txt");
//2.造流
FileInputStream fis = new FileInputStream(file);
//3.读数据
byte[] buffer = new byte[5];
int len;//记录每次读取的字节个数
while((len = fis.read(buffer)) != -1){
	String str = new String(buffer, 0, len);
	System.out.print(str);
}
//4.关闭资源
fis.close();
缓冲流

真正应用中,节点流由于效率比较低,很少单独使用,一般配合缓冲流使用
主要有四种:

  1. BufferedInputStream
  2. BufferedOutputStream
  3. BufferedReader
  4. BufferedWriter
    作用就是提高流的读取、写入速度
    原因:内部提供了一个缓冲区,大小为8192字节,内容存够8192后就一次性输出
    有一个方法是flush(),刷新缓冲区,即缓冲区还没存满,就把内容输出。一般不用

处理字节

//1.造文件
File srcFile = new File("hello.jpg");
File destFile = new File("hey.jpg");
//2.1 造节点流
FileInputStream fis = new FileInputStream(srcFile);
FileInputStream fos = new FileOutputStream(destFile);
//2.2 造缓冲流
BufferedInputStream bis = new BufferedInputStream(fis);
BufferedOutputStream bos = new BufferedOutputStream(fos);
//其实以上三步可以通过匿名类嵌套写成一步
//3.数据的操作
byte[] buffer = new byte[10];
int len;
while((len = bis.read(buffer)) != -1){
	bos.write(buffer, 0, len);
}
//4.资源关闭:要关4个,并且注意先后顺序
//要求:先关闭外层的流,再关闭内层的流
bos.close();
bis.close();
//其实关闭外层流的时候内层流会自动关闭,所以下面两个内层流关闭操作可以省略
fos.close();
fis.close();

以上可看出,处理流就是套接在已有流的基础上

处理字符

BufferedReader br = new BufferedReader(new FileReader(new File("hello.txt")));
BufferedWriter bw = new BufferedWriter(new FileWriter(new File("hey.txt")));

//方式一:使用char[]
char[] cbuf = new char[1024];
int len;
while((len = br.read(cbuf)) != -1){
	bw.writer(cbuf, 0, len);
}

//方式二:使用String
Stirng data;
while((data = br.readLine()) != null){//readLine()一次读一行,不包含换行符
	bw.write(data + "\n");//也可以用bw.newLine()实现换行
}

bw.close();
br.close();
转换流

在这里插入图片描述
转换流主要有:(属于字符流)

  1. InputStreamReader:将一个字节的输入流转换为字符的输入流,解码过程
  2. OutputStreamWriter:将一个字符的输出流转户为字节的输出流,编码过程
    转换流提供了在字节流和字符流之间的转换

InputStreamReader的使用示例:

File file = new File("hello.txt");
FileInputStream fis = new FileInputStream(file);
InputStreamReader isr = new InputStreamReader(fis);//它还有一个参数2,可以指明字符集。不指明就默认UTF-8
char cbuf = new char[20];
int len;
while((len = isr.read(cbugf)) != -1){
	String str = new String(cbuf, 0, len);
	System.out.print(str);
}
isr.close();

综合使用InputStreamReader、OutputStreamWriter示例:

File file1 = new File("hello.txt");
File file2 = new File("hey.txt");

FileInputStream fis = new FileInputStream(file1);
FileOutputStream fos = new FileOutputStream(file2);

InputStreamReader isr = new InputStreamReader(fis);
OutputStreamWriter osw = new OutputStreamWriter(fos);

char[] cbuf = new char[20];
int len;
while((len = isr.read(cbuf)) != -1){
	osw.write(cbuf, 0, len);
}
isr.close();
osw.close();
标准IO流、打印流、数据流

在这里插入图片描述

//输入字符串,变为大写输出,直到“e”或“exit”退出
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);

while(true){
	String data = br.readLine();
	if("e".equalsIgnoreCase(data) || "exit".equalsIgnoreCase(data)){
		System.out.println("程序结束");
		break;
	}
	String upperCase = data.toUpperCase();
	System.out.println(upperCase);
}
br.close();

打印流其实就是常用的print、println
在这里插入图片描述

PrintStream ps = null;
try{
	FileOutputStream fos = new FileOutputStream(new File("D:\\IO\\text.txt"));
	//创建打印输出流,设置为自动刷新模式(写入换行符或字节\n时都会刷新输出缓冲区)
	ps = new PrintStream(fos, true);
	if(ps != null){
		System.setOut(ps);
	}

	for(int i = 0; i <= 255; i++){
		System.out.print((char) i);
		if(i % 50 == 0){//每50个数据一行
			System.out.println();//换行
		}
	}catch(FileNotFoundException e){
		e.printStackTrace();
	}finally{
		if(ps != null){
			ps.close();
		}
	}
}

数据流
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

读取不同类型数据的顺序要和写入文件时保存数据的顺序一致

对象流(比如,把联系人数据从一个手机迁移到另一个手机)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

//序列化
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("hello.dat"));
oos.writeObject(new String("我爱中国"));
oos.flush();//刷新操作
oos.close();

//反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("hello.dat"));
Object obj = ois.readObejct();
String str = (String) obj;
ois.close();

自定义类需要满足以下要求方可实现序列化:

  1. 需要实现接口:Serializable
  2. 类中提供一个全局常量:static final long serialVersionUID。其值可以随便设一个
  3. 除了当前类需要实现Serializable之外,还必须保证其内部所有属性都是可序列化的(默认情况下,基本数据类型都可以序列化)

static和transient修饰的成员变量不能序列化

随机存取文件流
在这里插入图片描述
在这里插入图片描述

RandomAccessFile作为输出流时,写出到的文件如果不存在,则在执行过程中自动创建。如果文件存在,则会对原有文件内容进行覆盖(默认情况下从头覆盖)

在这里插入图片描述

在这里插入图片描述

这一章内容太多太杂,每好好做记录。以后遇到再整理吧

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值