File类
File 对象 = new File(路径名)
两个静态变量
pathSeparatorChar
提供系统级的路径分隔符字符。
pathSeparator
将其表示为字符串
前者文件分隔符unix下为 :,windows下为 ;,而后者无论哪个分隔符均为 /
四大构造方法
File(String pathname)
通过给定的路径名字符串创建 File 实例。如果路径名是空字符串,生成一个空的路径对象。File(String parent, String child)
通过父路径名和子路径名创建 File 实例。如果父路径名为 null,则只使用子路径名;否则,父路径表示目录,子路径表示文件或目录。若子路径是绝对路径,则会相对父路径进行解析。File(File parent, String child)
通过父路径对象和子路径名创建 File 实例。如果父路径对象为 null,则只使用子路径名;否则,父路径表示目录,子路径表示文件或目录。若子路径是绝对路径,也会相对父路径解析。File(URI uri)
通过给定的 file:// 格式的 URI 创建 File 实例。该 URI 格式根据操作系统不同而不同,转换规则也会有所不同。
常见方法
getAbsolutePath()
获取文件绝对路径
getPath()
获取文件封装路径,由初始化路径决定
getName()
获取文件名
length()
文件长度,即字节数目
createNewFile()
创建新文件
mkdir()
创建新目录
delete()
删除指定路径的文件
isDirectory()
判断是否为文件夹
isFile()
判断是否为文件
exists()
判断文件是否存在
list()
返回一个String数组,为对应文件夹下的文件的名称列表
listFiles()
返回对应文件夹下的File 数组
idea的相对路径为project的绝对路径开始的
IO流技术:一个设备的数据传输到另一个设备,常用于将内存中需要长久保存的数据输入输出到外存
字节流
所有的数据都可以转换为字节信息,是数据的基础,一切皆字节
两大抽象类
字节输出流:OutputStream
字节输入流:InputStream
字符流
专门操作文本文档
两大抽象类
字符输出流:Writer
字符输入流:Reader
字节和字符的关系,一个字符由于编码方式的不同会占不同个数的字节,这就要求我们在按字符读取时要提前了解文件的编码方式是UTF-8还是GBK等,如果编码不一致会产生乱码现象,而字节流是万能的,不受编码方式的影响,因此对于打印使用字符流,对于文件的复制使用字节流
文件的字节输入输出流
FileOutputStream:通过write方法输出字节到外设,有覆盖写和续写两种模式,不同操作系统的换行符不同,windows为\r\n,liunx为\n,mac为\r
FileInputStream:通过read方法输入字节到内存,返回的为对应字符的ASCII码值,末尾固定-1作为结束标志,-1~255其中-1为结束标记
package org.example;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
// 文件夹和文件都为一个文件对象,因此需要两个文件对象分别对文件夹,文件进行操作
// 文件夹对象
File file=new File("src/main/resources/data");
file.deleteOnExit();
file.mkdir();
file.deleteOnExit();
// 文件对象
file=new File("src/main/resources/data/data.txt");
file.createNewFile();
file.delete();
// 开启追加写而非覆盖
OutputStream out = new FileOutputStream(file,true);
// write有三个重载,空参,一个字节数组,一个字节数组并切出其中的一部分传入
out.write("A\r\nB\r\nC\r\nD\r\n".getBytes());
out.write("a\r\nb\r\nc\r\nd\r\n".getBytes());
out.close();
InputStream in = new FileInputStream(file);
int readByte;
// read有三个重载,空参,一个字节数组,一个字节数组并切出其中的一部分传入
while ((readByte=in.read()) != -1) {
// 将对应的ASCII码值转为对应的字符
System.out.println(readByte+" ==> "+(char)readByte);
}
in.close();
}
}
有个小细节要注意就是在一次读取一个字节数组时,是通过循环覆盖的方式,例如字节的数组长度为2,而文件中的字符分别为ABCD,一个字符占一个字节,一开始读入AB,然后在读取C时会覆盖A,即数组变成CB,读完C再读D就是CD了
文件的字符输入输出流
FileWriter:通过write方法输出字符到外设,有覆盖写和续写两种模式,可以传入字节数组和String字符串
FileReader:通过read方法输入字符到内存,返回的为对应字符的ASCII码值
字节和字符输出到外设有一个小细节,字节输出是直达的,写入一个字节文件就更新一个字节,而字符不一样,字符不会直接写入到文件当中,而是写入到内存的一个字符缓冲区中,因为字符往往占多个字节,如果逐个字符写入文件的话效率很低,需要等待上个字符写完才能进行下一个操作,因此我们使用字符缓冲区进行写入操作,而缓冲区进入文件中的操作为flush或者close,close的操作是先刷新再关闭,jdk8中通过trycatch可以实现自动关流
package org.example;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
File file=new File("src/main/resources/data/data.txt");
FileReader fr = new FileReader(file);
FileWriter fw = new FileWriter(file,true);
fw.write("你好\n\r我是字符输入输出流\n\r");
int readChar;
while ((readChar = fr.read()) != -1) {
System.out.println(readChar+" => "+(char) readChar);
}
fr.close();
// 刷新缓冲区到文件
fw.flush();
fr = new FileReader(file);
while ((readChar = fr.read()) != -1) {
System.out.println(readChar+" => "+(char) readChar);
}
fw.close();
fr.close();
}
}
缓冲:作为内存和外存的媒介,由于cpu 和内存交互快,而和外存交互满,因此有了缓冲区这个概念,外存直接和缓冲交互要比直接和内存交互快,我们操作一部分文件然后再将对应的文件放入缓冲区
字节缓冲流
之前所写的Fi1eOutputstream,Fi1eInputstream,FileReader,Filewriter这都叫做基本类,其中Fi1eInputstream和Fi1eoutputstream的读写方法都是本地方法(方法声明上带native),本地方法是和系统以及硬盘打交道的,也就是说这两个对象的读和写都是在硬盘之问进行读写的,效率不高;缓冲流中底层带一个长度为8192的数组(缓冲区),此时读和写都是在内存中完成的(在缓冲区之间完成),内存中的读写效率非常高
字节缓冲流的缓冲区为一个字节数组,默认大小为8192,字节缓冲流基于基本流
字节缓冲输出流:BufferedOutputStream
字节缓冲输入流:BufferedInputStream
package org.example;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
File file=new File("src/main/resources/data/data.txt");
InputStream in = new FileInputStream(file);
InputStream fis = new BufferedInputStream(new FileInputStream(file));
long start=System.currentTimeMillis();
int readByte;
while ((readByte = in.read()) != -1) {
System.out.println(readByte+" => "+(char) readByte);
}
in.close();
long end=System.currentTimeMillis();
System.out.println(end-start);
start=System.currentTimeMillis();
while ((readByte = fis.read()) != -1) {
System.out.println(readByte+" => "+(char) readByte);
}
fis.close();
end=System.currentTimeMillis();
System.out.println(end-start);
}
}
文件之前的交互转换为对应文件在内存中缓冲流的交互,文件通过基本流写入写出缓冲流,然后如果要进行文件之前数据的交互只需要在内存中进行两个文件之间缓冲流数据的交互,最好将缓冲流数据通过基本流刷新到文件内,避免了文件直接的慢速交互,内存要比硬盘快的多
字符缓冲流
字符缓冲输出流:BufferedWriter
字符缓冲输入流:BufferedReader
package org.example;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
File file=new File("src/main/resources/data/data.txt");
BufferedReader br=new BufferedReader(new FileReader(file));
// 逐行读取
String line=br.readLine();
while(line!=null){
System.out.println(line);
line=br.readLine();
}
br.close();
}
}
转换流
InputStreamReader:传入一个输入基本流和编码方式,字节流向字符的桥梁,即字节转换为字符,根据对应的编码方式
OutputStreamWriter:传入一个输出基本流和编码方式,字符流向字节的桥梁,即字符转换为字节,根据对应的编码方式
转换流:将字节和字符根据自定义的编码方式进行转换
序列化流和反序列化流
序列化和反序列化:主要作用就是存储对象,序列化是写对象,反序列化的是读对象
ObjectInputStream:反序列化,将对象读入到内存
ObjectOutputStream:序列化,将对象写入到外存
对于要存储的对象要实现一个Serializable接口,将对象转换为二进制数据在网络上传输,transient修饰的变量成员可以避免序列化
package org.example;
import java.io.*;
class Student implements Serializable{
String name;
int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class Main {
public static void main(String[] args) throws IOException, ClassNotFoundException {
File file=new File("src/main/resources/data/data.txt");
ObjectOutputStream out=new ObjectOutputStream(new FileOutputStream(file));
out.writeObject(new Student("李华",10));
out.close();
ObjectInputStream in=new ObjectInputStream(new FileInputStream(file));
System.out.println(in.readObject());
in.close();
}
}
序列化的注意事项
序列化的实例在编译为class文件中会自动生成一个序列号,该序列号会随实例一起存储到文件中,反序列化是通过编译的class文件中的序列号和外存文件的序列号进行匹配来进行的,如果我们修改源码重新编译的话会生成一个新的序列号,导致二者的序列号匹配失败导致反序列化失败
打印流
PrintStream:将文件中的内容打印输出
println():打印并自带换行效果
setout():改变流向,可以将打印输出到控制台转向打印输出到日志文件中
Properties集合
Properties
类是 Java 中用于处理配置文件的一个集合类,它继承自 Hashtable
,并专门用于存储和操作键值对数据。它通常用于应用程序的配置管理,允许将配置数据存储在 .properties
文件中,并能够轻松地从这些文件加载或保存配置。
主要特点:
-
键值对存储:
Properties
类存储的是键值对,其中键和值都是字符串类型。每个键对应一个值,这些键值对可以表示配置数据,如用户名、密码、数据库连接信息等。 -
加载与存储配置:
Properties
类提供了方便的方法来从文件加载配置数据,或者将配置数据写入文件。它通常用于.properties
文件,该文件是纯文本格式,包含以=
或:
分隔的键值对。 -
默认属性支持:
Properties
类支持默认属性。可以通过构造方法指定一个默认的Properties
对象,这样当查找某个键时,如果找不到,会返回默认值。 -
自动处理流:
Properties
类的load
和store
方法自动处理文件输入输出流,因此它非常适合用于读取和保存配置文件。
常用操作:
-
读取配置:使用
getProperty()
方法可以从Properties
对象中读取指定键的值。若该键不存在,可以返回一个默认值。 -
写入配置:使用
setProperty()
方法可以设置或更新键值对数据,使用store()
方法可以将当前的属性保存到文件中。 -
获取所有属性:可以使用
stringPropertyNames()
获取当前Properties
对象中的所有键名,并遍历这些键名来访问所有配置项。
应用场景:
-
配置管理:
Properties
最常用于存储和读取应用程序的配置文件,例如数据库连接信息、用户设置、语言选择等。 -
国际化支持:通过不同的
.properties
文件实现多语言支持,例如不同的语言文件可以存储不同的字符串,然后根据用户的语言设置加载合适的文件。 -
简单的存储和读取:适用于需要存储简单的键值对数据并且对性能要求不高的场景。
标签:文件,file,毕设,Java,字节,字符,IO,File,new From: https://www.cnblogs.com/liyiyang/p/18664969