文章目录
- 字节流、字符流、属性集
- 一、字节流
- 1. 字节输出流和文件字节输出流
- 2. 字节输出流写入数据到文件
- 3. 文件存储原理与记事本打开文件的原理
- 4. 字节输出流写多个字节的方法
- 5. 字节输出流的续写和换行
- 6. 字节输入流和文件字节输入流
- 7. 字节输入流读取字节数据
- 8. 字节输入流一次读取多个字节
- 9. 练习:文件复制
- 二、字符流
- 1. 使用字节流读取中文的问题
- 2. 字符输入流、文件字符输入流
- 3. 字符输入流读取字符数据
- 4. 字符输出流和文件字符输出流
- 5. 字符输出流将单个字符写入文件
- 6. flush方法和close方法的区别
- 7. 字符输出流写数据的其他方法
- 8. 字符输出流的续写和换行
- 9. JDK7 和 JDK9 流中异常的处理
- 三、属性集
字节流、字符流、属性集
一、字节流
1. 字节输出流和文件字节输出流
-
java.io.OutputStream
:字节输出流- 此抽象类是表示输出字节流的所有类的超类。
- 一些子类共性的成员方法:
public void close()
:关闭此输出流并释放与此流相关联的任何系统资源。public void flush()
:刷新此输出流并强制任何缓冲的输出字节被写出。public void write(byte[] b)
:将b.length
字节从指定的字节数组写入此输出流。public void write(byte[] b, int off, int len)
:从指定的字节数组写入len
字节,从偏移量off
开始输出到此输出流。public abstract void write(int b)
:将指定的字节输出流。
-
java.io.FileOutputStream extends OutputStream
-
FileOutputStream
:文件字节输出流。 -
作用:把内存中的数据写入到硬盘的文件中。
-
构造方法:
FileOutputStream(String name)
:创建一个向具有指定名称的文件中写入数据到输出文件流。FileOutputStream(File file)
:创建一个向指定File
对象表示的文件中写入数据的文件输出流。- 参数:
String name
:一个文件的路径。File file
:一个文件。
-
构造方法的作用:
- 创建一个
FileOutputStream
对象。 - 会根据构造方法中传递的文件/文件路径,创建一个空的文件。
- 会把
FileOutputStream
对象指向创建好的文件。
- 创建一个
-
2. 字节输出流写入数据到文件
- 写入数据的原理(内存 —> 硬盘):
java
程序 —>JVM
—>OS
—>OS
调用写数据的方法 —> 把数据写入到文件中
- 字节输出流的使用步骤:
- 创建一个
FileOutputStream
对象,构造方法中传递写入数据的目的地。 - 调用
FileOutputStream
对象中的方法write
,把数据写入到文件中。 - 释放资源(流使用会占用一定的内存,使用完毕要把内存清空,提高程序的效率)。
- 创建一个
import java.io.FileOutputStream;
import java.io.IOException;
public class Test {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("/Users/zgl/Desktop/a.txt");
fos.write(97);
fos.close();
}
}
3. 文件存储原理与记事本打开文件的原理
-
写数据的时候,会将10进制的整数转换为2进制输入存入硬盘。
-
任意的文本编辑器在打开文件的时候,把字节转换为字符表示。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rAnVj6do-1589461317122)(https://raw.githubusercontent.com/zhugulii/picBed/master/02_%E6%96%87%E4%BB%B6%E5%AD%98%E5%82%A8%E7%9A%84%E5%8E%9F%E7%90%86%E5%92%8C%E8%AE%B0%E4%BA%8B%E6%9C%AC%E6%89%93%E5%BC%80%E6%96%87%E4%BB%B6%E7%9A%84%E5%8E%9F%E7%90%86.bmp)]
4. 字节输出流写多个字节的方法
public void write(byte[] b)
:将b.length
字节从指定的字节数组写入此输出流。- 如果写的第一个字节是正数(0~127),那么显示的时候会查询ASCII表。
- 如果写的第一个字节是负数,那么第一个字节会和第二个字节组成一个中文显示,查询系统默认码表(GBK)。
public void write(byte[] b, int off, int len)
:从指定的字节数组写入len
字节,从偏移量off
开始输出到此输出流。int off
:数组的开始索引。int len
:写入len
个字节。
- 写入字符的方法:可以使用
String
类中的方法把字符串转换为字节数组。byte[] getBytes()
:把字符转换为字节数组。
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class Test {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream(new File("/Users/zgl/Desktop/b.txt"));
byte[] bytes1 = {97,98,99};
byte[] bytes2 = {-97,98,-99};
byte[] bytes3 = "你好".getBytes();
fos.write(bytes1);
fos.write(bytes2);
fos.write(bytes3);
fos.write(bytes1,1,1);
fos.close();
}
}
5. 字节输出流的续写和换行
-
追加写/续写:使用两个参数的构造方法。
FileOutputStream(String name, boolean append)
:创建一个向具有指定name
的文件写入数据的输出文件流。FileOutputStream(File file, boolean append)
:创建一个向具有指定file
的文件写入数据的输出文件流。- 参数:
String name、File name
:写入数据的目的地。boolean append
:追加写开关。true
:创建对象不会覆盖源文件,继续在文件的末尾追加写数据。false
:创建一个新文件,覆盖源文件。
- 参数:
import java.io.FileOutputStream; import java.io.IOException; public class Test { public static void main(String[] args) throws IOException { FileOutputStream fos = new FileOutputStream("/Users/zgl/Desktop/a.txt",true); for (int i = 0; i < 5; i++) { fos.write("你好".getBytes()); } fos.close(); } }
-
写换行:写换行符号
- win:
\r\n
- Linux:
\n
- Mac:
\r
import java.io.FileOutputStream; import java.io.IOException; public class Test { public static void main(String[] args) throws IOException { FileOutputStream fos = new FileOutputStream("/Users/zgl/Desktop/a.txt",true); for (int i = 0; i < 5; i++) { fos.write("你好".getBytes()); fos.write("\r".getBytes()); } fos.close(); } }
- win:
6. 字节输入流和文件字节输入流
java.io.InputStream
:字节输入流。此抽象类是表示字节输入流的所有类的超类。- 一些子类共性的方法:
int read()
:从输入流中读取数据的下一个字节并返回,读取到文件的末尾返回-1。int read(byte[] b)
:从输入流中读取一定数量的字节,并将其存储在缓冲区的数组b
中。void close()
:关闭此输入流并释放与该流关联的所有系统资源。
- 一些子类共性的方法:
java.io.FileInputStream extends InputStream
FileInputStream
:文件字节输入流- 作用:把硬盘中的数据,读取到内存中使用。
- 构造方法:
FileInputStream(String name)
FileInputStream(File file)
- 参数:读取文件的数据源
String name
:文件的路径File file
:文件
- 构造方法的作用:
- 会创建一个
FileInputStream
对象。 - 会把
FileInputStream
对象指向构造方法中要读取的文件。
- 会创建一个
7. 字节输入流读取字节数据
- 读取数据的原理(硬盘 —> 内存):
java
程序 —>JVM
—>OS
—>OS
读取数据的方法 —> 读取文件
- 字节输入流的使用步骤:
- 创建
FileInputStream
对象,构造方法中绑定要读取的数据源。 - 使用
FileInputStream
对象中的方法read
,读取文件。 - 释放资源。
- 创建
import java.io.FileInputStream;
import java.io.IOException;
public class Test {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("/Users/zgl/Desktop/a.txt");
int tmp;
while ((tmp = fis.read()) != -1) {
System.out.print((char) tmp); // abc
}
fis.close();
}
}
8. 字节输入流一次读取多个字节
int read(byte[] b)
:从输入流中读取一定数量的字节,并将其存储在缓冲区的数组b
中。- 参数
byte[] b
,起到缓冲作用,存储每次读取到的多个字节。 - 数组的长度一般定义为1024(1KB)或者1024的整数倍。
- 返回值为每次读取到的有效字节个数。
- 参数
String
类的构造方法:String(byte[] bytes)
:把字节数组转换为字符串。String(byte[] bytes, int offset, int length)
:把字节数组的一部分转换为字符串,offset
为数组的开始索引,length
:转换的字节个数。
import java.io.FileInputStream;
import java.io.IOException;
public class Test {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("/Users/zgl/Desktop/a.txt");
byte[] bytes = new byte[1024];
int len;
while ((len = fis.read(bytes)) != -1) {
System.out.println(new String(bytes,0,len)); // abcdefgh
}
fis.close();
}
}
9. 练习:文件复制
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Test {
public static void main(String[] args) throws IOException {
long s = System.currentTimeMillis();
FileInputStream fis = new FileInputStream("/Users/zgl/Desktop/a.txt");
FileOutputStream fos = new FileOutputStream("/Users/zgl/Desktop/b.txt");
int len = 0;
byte[] bytes = new byte[1024];
while ((len = fis.read(bytes)) != -1) {
fos.write(bytes,0,len);
}
fis.close();
fos.close();
long e = System.currentTimeMillis();
System.out.println("复制文件共用时:" + (e-s) + "毫秒!");
}
}
二、字符流
1. 使用字节流读取中文的问题
- 可能会出现乱码问题。
- 1个中文字符:
GBK
:占用两个字节。UTF-8
:占用三个字节。
2. 字符输入流、文件字符输入流
java.io.Reader
:字符输入流,是字符输入流的最顶层的父类,定义了一些共性的成员方法,是一个抽象类。- 共性的成员方法:
int read()
:读取单个字符并返回。int read(char[] cbuf)
:一次读取多个字符,将字符读入数组。void close()
:关闭该流并释放与之关联的所有资源。
java.io.FileReader extends InputStream extends Reader
FileReader
:文件字符输入流。- 作用:把硬盘文件中的数据以字符的方式读取到内存中。
- 构造方法:
FileReader(String fileName)
FileReader(File file)
- 参数:
String filename
:文件的路径File file
:文件
FileReader
:构造方法的作用:- 创建一个
FileReader
对象。 - 会把
FileReader
对象指向要读取的文件。
- 创建一个
3. 字符输入流读取字符数据
- 使用步骤:
- 创建
FileReader
对象,构造方法中绑定要读物的数据源。 - 使用
FileReader
对象中的方法read
读取文件。 - 释放资源。
- 创建
String
类的构造方法:String(char[] value)
:把字符数组转换为字符串。String(char[] value, int offset, int count)
:把字符数组的一部分转换为字符串,offset
为数组的开始索引,length
:转换的符节个数。
import java.io.FileReader;
import java.io.IOException;
public class Test {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("/Users/zgl/Desktop/a.txt");
//使用read()
/*int tmp1;
while ((tmp1 = fr.read()) != -1) {
System.out.print((char)tmp1); // 你好,朱古力!
}*/
//使用read(char[] chars)
int len;
char[] chars = new char[1024];
while ((len = fr.read(chars)) != -1) {
System.out.println(new String(chars,0,len)); // 你好,朱古力!
}
fr.close();
}
}
4. 字符输出流和文件字符输出流
java.io.Writer
:字符输出流,是所有字符输出流的最顶层的父类,是一个抽象类。- 共性的成员方法:
void write(int c)
:写入单个字符。void write(char[] cbuf)
:写入字符数组。void write(char[] cbuf, int off, int len)
:写入字符数组的某一部分,off
为数组的开始索引,len
为写的字符个数。void write(String str)
:写入字符串。void write(String str, int off, int len)
:写入字符串的某一部分,off
为字符串的开始索引,len
为写的字符个数。void flush()
:刷新该流的缓冲。void close()
:关闭此流,但要先刷新它。
java.io.FileWriter extends OutputStreamWriter extends Writer
FileWriter
:文件字符输出流。- 作用:把内存中字符数据写入到文件中。
- 构造方法:
FileWriter(File file)
:根据给定的file
对象构造一个FileWriter
对象。FileWriter(String filename)
:根据给定的文件名构造一个FileWriter
对象。- 参数:
String filename
:文件的路径。File file
:文件。
- 作用:
- 会创建一个
FileWriter
对象。 - 会根据构造方法中传递的文件/文件的路径,创建文件。
- 会把
FileWriter
对象指向创建好的文件。
- 会创建一个
5. 字符输出流将单个字符写入文件
-
使用步骤:
- 创建
FileWriter
对象,构造方法中绑定要写入数据的目的地。 - 使用
FileWriter
中的方法write
,把数据写入到内存缓冲区中(字符转换为字节的过程)。 - 使用
FileWriter
中的方法flush
,把内存缓冲区中的数据,刷新到文件中。 - 释放资源(会先把内存缓冲区中的数据刷新到文件中)。
import java.io.FileWriter; import java.io.IOException; public class Test { public static void main(String[] args) throws IOException { FileWriter fw = new FileWriter("/Users/zgl/Desktop/b.txt"); fw.write(97); fw.flush(); fw.close(); } }
- 创建
6. flush方法和close方法的区别
-
flush
:刷新缓冲区,流对象可以继续使用。 -
close
:先刷新缓冲区,然后通知系统释放资源,流对象不可以再被使用。import java.io.FileWriter; import java.io.IOException; public class Test { public static void main(String[] args) throws IOException { FileWriter fw = new FileWriter("/Users/zgl/Desktop/c.txt"); fw.write(97); fw.flush(); //可以继续使用流对象 fw.write(98); fw.close(); //抛出异常 IOException: Stream closed fw.write(99); } }
7. 字符输出流写数据的其他方法
-
void write(char[] cbuf)
:写入字符数组。 -
void write(char[] cbuf, int off, int len)
:写入字符数组的某一部分,off
为数组的开始索引,len
为写的字符个数。 -
void write(String str)
:写入字符串。 -
void write(String str, int off, int len)
:写入字符串的某一部分,off
为字符串的开始索引,len
为写的字符个数。import java.io.FileWriter; import java.io.IOException; public class Test { public static void main(String[] args) throws IOException { FileWriter fw = new FileWriter("/Users/zgl/Desktop/d.txt"); char[] chars = {'a','b','c'}; fw.write(chars); // abc fw.write(chars,1,2); // bc String str = "zhuguli"; fw.write(str); // zhuguli fw.write(str,3,4); // guli fw.flush(); fw.close(); } }
8. 字符输出流的续写和换行
- 追加写/续写:使用两个参数的构造方法。
FileWriter(String name, boolean append)
FileWriter(File file, boolean append)
- 参数:
String name、File name
:写入数据的目的地。boolean append
:追加写开关。true
:创建对象不会覆盖源文件,继续在文件的末尾追加写数据。false
:创建一个新文件,覆盖源文件。
- 参数:
- 写换行:写换行符号
- win:
\r\n
- Linux:
\n
- Mac:
\r
- win:
import java.io.FileWriter;
import java.io.IOException;
public class Test {
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("/Users/zgl/Desktop/e.txt",true);
for (int i = 0; i < 5; i++) {
fw.write("你好");
}
for (int j = 0; j < 5; j++) {
fw.write("你好" + "\r");
}
fw.flush();
fw.close();
}
}
9. JDK7 和 JDK9 流中异常的处理
-
JDK
7的新特性:-
在
try
后边可以增加一个()
,在括号中可以定义流对象。 -
这个流对象的作用域就在
try
中有效。 -
try
中的代码执行完毕,会自动把流对象释放,不用写finally
。 -
格式:
try(定义流对象;定义流对象;...){ 可能会产生异常的代码 }catch(异常类变量 变量名){ 异常处理逻辑 }
-
-
JDK9
的新特性:-
try
的前边可以定义流对象。 -
在
try
后边的()
可以直接引入流对象的名称(变量名)。 -
try
中的代码执行完毕,会自动把流对象释放,不用写finally
。 -
格式:
A a = new A(); B b = new B(); try(a,b){ 可能会产生异常的代码 }catch(异常类变量 变量名){ 异常处理逻辑 }
-
三、属性集
1. 使用Properties集合存储数据,遍历取出Properties集合中的数据
-
java.util.Properties集合 extends Hashtable<k,v> implements Map<k,v>
-
Properties
类表示了一个持久的属性集,Properties
可保存在流中或从流中加载。 -
Properties
集合是唯一一个与IO
流相结合的集合。- 可以使用
Properties
集合中的方法store
,把集合中的临时数据,持久化写入到硬盘中存储。 - 可以使用
Properties
集合中的方法load
,把硬盘中保存的文件(键值对),读取到集合中使用。
- 可以使用
-
属性列表中每个键及其对应值都是一个字符串。
Properties
集合是一个双列集合,key
和value
默认都是字符串。
-
Properties
集合有一些操作字符串特有的方法:Object setProperty(String key, String value)
调用Hashtable
的方法put
。String getProperty(String key)
通过key
找到value
值,此方法相当于Map
集合中的get(key)
方法。set<String> stringPropertyName()
返回此属性列表中的键集。
import java.util.Properties; import java.util.Set; public class Test { public static void main(String[] args) { Properties prop = new Properties(); prop.setProperty("朱古力","18"); prop.setProperty("猪猪侠","20"); prop.setProperty("猪猪猪","22"); Set<String> strings = prop.stringPropertyNames(); for (String key : strings) { String value = prop.getProperty(key); System.out.println(key + "=" + value); } } }
2. Properties集合中的方法store
-
可以使用
Properties
集合中的方法store
,把集合中的临时数据,持久化写入到硬盘中存储。 -
void store(OutputStream out, String comments)
-
void store(Writer writer, String comments)
- 参数:
OutputStream out
:字节输出流,不能写入中文。Writer writer
:字符输出流,可以写中文。String comment
:注释,用来解释说明保存的文件是做什么用的。- 不能使用中文,会产生乱码,默认是
Unicode
编码 - 一般使用
""
空字符串。
- 不能使用中文,会产生乱码,默认是
- 参数:
-
使用步骤:
- 创建
Properties
集合对象,添加数据。 - 创建字节/字符输出流对象,构造方法中绑定要输出的目的地。
- 使用
Properties
集合中的方法store
,把集合中的临时数据,持久化写入到硬盘中存储。 - 释放资源。
import java.io.FileWriter; import java.io.IOException; import java.util.Properties; public class Test { public static void main(String[] args) throws IOException { Properties prop = new Properties(); prop.setProperty("朱古力","18"); prop.setProperty("猪猪侠","20"); prop.setProperty("猪猪猪","22"); FileWriter fw = new FileWriter("/Users/zgl/Desktop/f.txt"); prop.store(fw,"save"); fw.close(); } }
- 创建
3. Properties集合中的方法load
-
可以使用
Properties
集合中的方法load
,把硬盘中保存的文件(键值对),读取到集合中使用。 -
void load(InputStream inStream)
-
void load(Reader reader)
- 参数:
InputStream inStream
:字节输入流,不能读取含有中文的键值对。Reader reader
:字符输入流,能读取含有中文的键值对。
- 参数:
-
使用步骤:
- 创建
Properties
集合对象。 - 使用
Properties
集合对象中的方法load
读取保存键值对的文件。 - 遍历
Properties
集合。
- 创建
-
注意:
- 存储键值对的文件中,键与值默认的连接符号可以使用
=
、空格
、其他符号。 - 存储键值对的文件中,可以使用
#
进行注释,被注释的键值对不会再被读取。 - 存储键值对的文件中,键与值默认都是字符串,不用再加引号。
import java.io.FileReader; import java.io.IOException; import java.util.Properties; import java.util.Set; public class Test { public static void main(String[] args) throws IOException { Properties prop = new Properties(); FileReader fw = new FileReader("/Users/zgl/Desktop/f.txt"); prop.load(fw); Set<String> keys = prop.stringPropertyNames(); for (String key : keys) { String value = prop.getProperty(key); System.out.println(key + "=" + value); } fw.close(); } }
- 存储键值对的文件中,键与值默认的连接符号可以使用
转载:https://blog.csdn.net/weixin_44781238/article/details/106128592