目录
一.文件
1.介绍
文件就是保存数据的地方。这个数据可以是文本,也可以是图片或视频。
文件在程序中是以流的形式来操作的,称之为文件流。文件流有两种:
输入流:数据从数据源(文件)到程序(内存)的路径
输出流:数据从程序(内存)到数据源(文件)的路径
这里是输入输出是相对于java程序也就是内存而言的。
2.创建文件
方法一:
//方法一:new File(String pathname) 路径
public void create01(){
String pathname="E:\\news1.txt";
File file = new File(pathname);
try {
file.createNewFile();
System.out.println("创建成功");
} catch (IOException e) {
e.printStackTrace();
}
}
方法二:
//方法二:new File(File parent,String child) 父目录文件+子路径
public void create02(){
File parent = new File("E:\\");
String child="news2.txt";
File file = new File(parent, child);
try {
file.createNewFile();
System.out.println("创建成功");
} catch (IOException e) {
e.printStackTrace();
}
}
方法三:
//方法三:new File(String parent,String child) 父目录+子路径
public void create03(){
String parent="E:\\";
String child="news3.txt";
File file = new File(parent, child);
try {
file.createNewFile();
System.out.println("创建成功");
} catch (IOException e) {
e.printStackTrace();
}
}
3.常用文件操作
获取文件相关信息:
方法 | 说明 |
getName() | 获取文件名字 |
getAbsoluteFile() | 获取文件绝对路径 |
getParent() | 获取文件父级目录 |
length() | 获取文件大小(字节) |
exists() | 判断文件是否存在 |
isFile() | 判断是不是一个文件 |
isDirectory() | 判断是不是一个目录 |
目录的操作和文件删除:
方法 | 说明 |
mkdir() | 创建一级目录 |
mkdirs() | 创建多级目录 |
delete() | 删除空目录或文件 |
补充:目录是以文件为数据的文件,可以把目录理解成文件夹。mkdir()创建目录的最后一个父目录必须存在,其只能创建一级目录。mkdirs()可以创建一级或多级。
二.流(Stream)
JavaIO流用于处理数据传输,如读写文件,网络通讯等。Java程序中,对于数据的输入/输出操作以“流”的方式进行。
1.IO流的原理
输入input :读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中
输出 output :将程序(内存)数据输出到磁盘、光盘等存储设备中
2.流的分类
按操作数据单位不同分为:字节流(8 bit)二进制文件(如声音、视频、pdf等)、字符流(按字符)文本文件
按数据流的流向不同分为:输入流、输出流
按流的角色的不同分为:节点流、处理流(包装流)
抽象基类 | 字节流 | 字符流 |
输入流 | InputStream | Reader |
输出流 | OutputStream | Writer |
说明:Java的IO流共涉及40多个类,其都是由上面的4个抽象基类派生的。
各个流的分类一定要弄清楚!
三.文件字节流
字节流有两个基类:InputStream(输入) 和 OutputStream(输入)。
下面介绍一下这两个基类的文件输入输出流。
1.FileInputStream(输入)
读取方式:先创建FileInputStream对象,用于读取文件;再使用FileInputStream.read()方法进行读取,read方法返回的是int类型的值,如果返回-1,说明读取完毕;最后不要忘记关闭文件流释放资源。
代码示例:
String filePath="C:\\news1.txt\\news2.txt";
int readData=0;
FileInputStream fileInputStream=null;
try {
fileInputStream=new FileInputStream(filePath);
while((readData=fileInputStream.read())!=-1){
System.out.println((char)readData);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
上述代码的效率太低,这是因为它是一个一个字节的读,太慢了,我们有没有什么办法让它一次多好几个呢?当然有,我们可以使用一个字节数组,其大小不固定,看我们需要多少,这里我用的是大小为8的:
String filePath="C:\\news1.txt\\news2.txt";
byte[] b=new byte[8];
int readLen=0;
FileInputStream fileInputStream=null;
try {
fileInputStream=new FileInputStream(filePath);
while((readLen=fileInputStream.read(b))!=-1){
System.out.print(new String(b,0,readLen));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//使用readLen的好处:如果后面的字节不足8,那么就会产生乱码。使用readLen可以得到字节的长度,不会出现乱码
2.FileOutputStream(输出)
写入方式:先创建FileOutputStream对象,用于写入数据;再开始写入数据;最后关闭文件流。
FileOutputStream默认是覆盖文件,也就是我们新写入的内容会覆盖掉原来的文件内容。如果想不覆盖,改为追加在文件后面的话,就加个true(详情看代码示例)
代码示例:
String filePath="C:\\news1.txt\\news2.txt";
//覆盖
FileOutputStream fileOutputStream = new FileOutputStream(filePath);
//不覆盖
FileOutputStream fileOutputStream = new FileOutputStream(filePath,true);
//写入单个字符
fileOutputStream.write('h');
//批量写入整个byte数组
fileOutputStream.write("hello".getBytes());
//部分写入,第二个参数是从第几个开始写入,第三个参数是写进几个
fileOutputStream.write("world".getBytes(),0,3);
fileOutputStream.close();
四.文件字符流
1.FileReader(输入)
读取的过程与文件字节流差不多,这里只有一点要说,就是这是字符输入流,可别将要存放读取数据的数组设置成byte。
代码示例:
public void reader01(){
String filePath="C:\\news1.txt\\news2.txt";
FileReader fileReader=null;
int data=0;
//创建一个FileReader对象
try {
fileReader=new FileReader(filePath);
while((data = fileReader.read())!=-1){
System.out.println((char)data);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fileReader!=null){
try {
fileReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public void reader02(){
String filePath="C:\\news1.txt\\news2.txt";
FileReader fileReader=null;
int dataLen=0;
char[] ch=new char[8];
//创建一个FileReader对象
try {
fileReader=new FileReader(filePath);
while((dataLen = fileReader.read(ch))!=-1){
System.out.println(new String(ch,0,dataLen));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fileReader!=null){
try {
fileReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
2.FileWriter(输出)
写入方式也与文件字节流的输出流相似,各个方法的内容也相似。
但是要注意FileWriter使用完后一定要关闭(close)或刷新(flush),否则写入不到指定的文件。在底层,close是后flush和关闭操作组合成的。从本质上来讲,让文件无法写入的关键是:是否刷新。
代码示例:
public void writer(){
String filePath="C:\\news1.txt\\news2.txt";
FileWriter fileWriter=null;
try {
fileWriter=new FileWriter(filePath);
//1.写入单个字符
fileWriter.write('E');
//2.写入指定数组
char[] ch={'1','2'};
fileWriter.write(ch);
//3.写入指定数组的指定部分
fileWriter.write("abcde".toCharArray(),1,1);
//4.写入整个字符串
fileWriter.write("hello");
//5.写入字符串的指定部分
fileWriter.write("world",0,3);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fileWriter.close();
System.out.println("关闭文件");
} catch (IOException e) {
e.printStackTrace();
}
}
}
五.处理流(包装流)
1.节点流和处理流
节点流可以用从一个特定的数据源读写数据,如FileReader、FileWriter等。节点流是底层流,是直接与数据源相接的。
处理流(包装流)是“连接”在以存在的流之上,为程序提供更为强大的读写功能,如BufferedReader、BufferedWriter等。包装流相当灵活,可以使用其父类来实例化对象。处理流即可以消除不同节点流的实现差异,也可以提供更方便的方法来完成输入输出。处理流不与数据源直接相连。
处理流的功能:
性能的提高:主要以增加缓冲的方式来提高输入输出的效率。
操作的便捷:处理流可能提供一系列便捷的方式来一次输入输出大批量的数据,使用更加灵活。
2.BufferedReader(输入)
代码示例:
String filePath="C:\\news1.txt\\news2.txt";
//创建对象
BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath));
String line;
while((line = bufferedReader.readLine())!=null){
System.out.println(line);
}
//关闭流,底层会自动调用节点流
bufferedReader.close();
用的虽然是包装流,但实际工作的是节点流
3.BufferedWriter(输出)
代码示例:
String filePath="C:\\news1.txt\\news2.txt";
//创建对象
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath));
//写入数据
bufferedWriter.write("114514");
bufferedWriter.newLine(); //在写入时换行
bufferedWriter.write("1919810");
//关闭流
bufferedWriter.close();
六.对象流
1.序列化和反序列化
序列化:保存数据时保存数据的值和数据类型
反序列化:恢复数据时恢复数据的值和数据类型
为了让某个类实现可序列化,该类必须实现如下两个接口之一:
Serializable(这是一个标记接口,其没有要实现的方法)
Externalizable(该接口有要实现的方法,不推荐使用)
2.ObjectOutputStream(输出)
ObjectOutputStream是序列化,将数据的值和类型写入文件
代码示例:
String filePath="C:\\news1.txt\\news2.dat";
//创建对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath));
//序列化数据
oos.writeInt(100); //int Integer实现了Serializable
oos.writeBoolean(true);
oos.writeUTF("hello"); //String类型
oos.close();
3.ObjectInputStream(输入)
ObjectInputStream的反序列化,将文件中存储的数据读到程序中去,这里要注意,反序列话取的内容顺序要与序列化相同,如果不同,如第一个本来是int类型的,结果反序列化取了一个double类型的,数据肯定是错的。
代码示例:
String filePath="C:\\news1.txt\\news2.dat";
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(filePath));
//反序列化的顺序要与序列化的顺序一致
System.out.println(objectInputStream.readInt());
System.out.println(objectInputStream.readBoolean());
System.out.println(objectInputStream.readUTF());
//关闭资源
objectInputStream.close();
4.注意事项
1)读写顺序一致;
2)要求序列化或反序列化对象,需要实现 Serializable 接口;
3)序列化的类中默认添加SerialVersionUID,为了提高版本的兼容性;
4)序列化对象时,默认将里面所有属性都进行序列化,但除了static或transient修饰的成员;
5)序列化对象时,要求里面属性的类型也要实现序列化接口;
6)序列化具备可继承性,也就是如果某类已经实现了序列化,则它的所有子类也已经默认实现了序列化。
七.转换流
1.介绍
当处理纯文本文件数据时,如果使用字符流效率更高,并且可以有效解决中文问题,所有建议将字节流转化成字符流。使用转换流时可以指定编码格式,如utf-8,gbk等。
2.InputStreamReader(输入)
Reader的子类,可以将InputStream(字节流)包装成Reader(字符流)。
代码示例:
String filePath="C:\\news1.txt\\news2.txt";
//将FileInputStream 转成InputStreamReader
InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream(filePath),"gbk");
//将InputStreamReader 传入
BufferedReader br = new BufferedReader(inputStreamReader);
String s = br.readLine();
System.out.println(s);
//关闭外层流
br.close();
2.OutputStreamWriter(输出)
Writer的子类,可以将OutputStream(字节流)包装成Writer(字符流)。
代码示例:
String filePath="C:\\news1.txt\\news2.txt";
//将FileInputStream 转成InputStreamReader
InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream(filePath),"gbk");
//将InputStreamReader 传入
BufferedReader br = new BufferedReader(inputStreamReader);
String s = br.readLine();
System.out.println(s);
//关闭外层流
br.close();
八.打印流
打印流只有输出流,没有输入流。
1.PrintStream
代码示例:
PrintStream out=System.out;
//默认情况下,PrintStream 输出数据的位置是 标准输出,即显示器
out.print("嗨嗨嗨");
//关闭流
out.close();
//修改打印流输出的位置/设备
String filePath="C:\\news1.txt\\news2.txt";
System.setOut(new PrintStream(filePath));
//下面这句会输出到文件中
System.out.println("小汉堡");
2.PrintWriter
代码示例:
String filePath="C:\\news1.txt\\news2.txt";
//输出到屏幕上
PrintWriter printWriter = new PrintWriter(System.out);
//输出到文件中
PrintWriter printWriter = new PrintWriter(new FileWriter(filePath));
printWriter.print("嗨嗨嗨");
//关闭流
printWriter.close();
九.Properties 类
1.介绍
专门用于读写配置文件的集合类。配置文件的格式:键=值,这里注意:键值对不需要有空格,值不需要用引号括起来,默认类型时String
2.常见方法
方法 | 说明 |
load | 加载配置文件的键值对到Properties对象 |
list | 将数据显示到指定设备/流对象 |
getProperty(key) | 根据键获取值 |
setProperty(key,value) | 设置键值对到Properties对象 |
store | 将Properties中的键值对存储到配置文件,在idea中,如果保存到配置文件的信息中含有中文,会存储Unicode码 |
3.读文件
代码示例:
//创建对象
Properties properties = new Properties();
//加载指定配置文件
properties.load(new FileReader("C:\\news1.txt\\news2.txt"));
//把k-v显示控制台
properties.list(System.out);
//根据key获取对应的值
properties.getProperty("a");
4.创建和修改文件
代码示例:
Properties properties = new Properties();
//使用setProperty时,如果name不存在,那就是创建;如果name存在,那就是修改
properties.setProperty("name","Tom");
//将k-v存储文件中,后面的null是注释,没有注释就写null
properties.store(new FileOutputStream("C:\\news1.txt\\news2.txt"),null);