1. IO概述
1.1 什么是IO
数据的传输可以看作是一种数据的流动,按照流动的方向,以内存为基准,分为输入input
和输出output
,即流向内存的是输入流,流出内存的是输出流
Java
中I/O
操作主要是指使用java.io
包下的内容,进行输入输出操作.输入也叫读取数据,输出也叫写出数据
1.2 IO的分类
根据数据的流向分为:输入流和输出流
- 输入流:把数据重其他设备上读取到内存中的流
- 输出流:把数据从内存中写出到其他设备上的流
根据数据的类型分为:字节流和字符流
- 字节流:以字节为单位,读写数据的流
- 字符流:以字符为单位,读写数据的流
1.3 顶级父类
输入流 | 输出流 | |
---|---|---|
字节流 | InputStream |
OutputStream |
字符流 | Reader |
Writer |
2. 字节流
2.1 一切皆为字节
一切文件数据(文本,图片,视频等)在存储时都是以二进制数字的形式保存,都是一个一个的字节,那么传输时一样如此.所以在节流可以传输任意文件数据.在操作流的手,我们要时刻明确无论什么样的流对象,底层传输的始终为二进制数据
2.2 字节输出流(OutputStream)
java.io.OutputStream
抽象类是表示字节输出流的所有类的超类,将指定的字节信息写出到目的地.它定义了字节输出流的基本共性功能方法.
public void close()
:关闭此输出流并释放与此流相关联的任何系统资源public void flush()
:刷新此输出流并强制任何缓冲的输出字节被写出public void writer(byte[] b)
:将b.length
字节从指定的字节数组写入此输出流public void write(byte[] b,int off ,int len)
:从指定的字节数写入len
字节,从偏移量off
开始输出到此输出流public abstract void wtite(int b)
:将指定的字节输出流
close方法
当完成流的操作时,必须调用此方法,释放系统资源
2.3 FileOutputStream
java.io.FileOutputStream
类是文件输出流,是OutputStream
的子类,用于将数据写出到文件
构造方法
public FileOutputSream(File file)
:创建文件输出流以写入由指定的File对象
表示的文件public FileOutputStream(String name)
:创建文件输出流以指定的名称写入文件
当你创建一个流对象是,必须传入一个文件路径,该路径下,如果没有这个文件,会创建这个文件.如果有这个文件,会清空这个文件的数据
public class Test1 {
public static void main(String[] args) throws IOException {
// 使用File对象创建流对象
File file = new File("a.txt");
FileOutputStream fos = new FileOutputStream(file);
// 使用文件名称创建流对象
FileOutputStream os = new FileOutputStream("b.txt");
}
}
写出字节数据
写出字节:write(int b)
方法,每次可以写出一个字节数据
public class Test1 {
public static void main(String[] args) throws IOException {
// 使用文件名称创建流对象
FileOutputStream fos = new FileOutputStream("b.txt");
// 写出数据
fos.write(97); // 写出第1个字节
fos.write(98); // 写出第2个字节
fos.write(99); // 写出第3个字节
// 关闭资源
fos.close();
}
}
- 虽然参数为
int
类型四个字节,但是只会保留一个字节的信息写出
写出字节数组:write(byte[] b)
,每次可以写出数组中的数据
public class Test1 {
public static void main(String[] args) throws IOException {
// 使用文件名称创建流对象
FileOutputStream fos = new FileOutputStream("b.txt");
// 字符串转换为字节数组
byte[] bytes = "我爱你".getBytes();
// 写出字节数组数据
fos.write(bytes);
// 关闭资源
fos.close();
}
}
写出指定长度字节数组:write(byte[] b,int off,int len)
,每次写出从off
索引开始,len
个字节
public class Test1 {
public static void main(String[] args) throws IOException {
// 使用文件名称创建流对象
FileOutputStream fos = new FileOutputStream("b.txt");
// 字符串转换为字节数组
byte[] bytes = "abcde".getBytes();
// 写出从索引2开始,2个字节.索引2是c,两个字节,也就是cd
fos.write(bytes,2,2);
// 关闭资源
fos.close();
}
}
数据追加续写
public FileOutputStream(File file,boolean append)
:创建按文件输出流写入由指定的File对象表示的文件public FileOutputStream(String name,boolean append)
:创建文件输出流以指定发的名称写入文件
这两个构造方法,参数中都需要传入一个boolean
类型的值,true
表示追加数据,false
表示清空原有数据,这样创建的输出流对象,就可以指定是否追加续写了
public class Test1 {
public static void main(String[] args) throws IOException {
// 使用文件名称创建流对象
FileOutputStream fos = new FileOutputStream("b.txt",true);
// 字符串转换为字节数组
byte[] bytes = "abcde".getBytes();
// 写出从索引2开始,2个字节.索引2是c,两个字节,也就是cd
fos.write(bytes,2,2);
// 关闭资源
fos.close();
}
}
写出换行
Windows
系统里,换行符号\r\n
.
public class Test1 {
public static void main(String[] args) throws IOException {
// 使用文件名称创建流对象
FileOutputStream fos = new FileOutputStream("b.txt",true);
// 定义字节数组
byte[] bytes = {97,98,99,100,101};
// 遍历数组
for (int i = 0; i < bytes.length; i++) {
// 写出一个字节
fos.write(bytes[i]);
// 写出一个换行,换行符号转换成数组写出
fos.write("\r\n".getBytes());
}
// 关闭资源
fos.close();
}
}
回车符\r
和换行符\n
:- 回车符:回到一行的开头(
return
) - 换行符:下一行(
newline
)
- 回车符:回到一行的开头(
- 系统中的换行
- Windows系统里,每行结尾是
回车+换行
,即\r\n
- Unix 系统里,每行结尾只有
回车
,即\n
- Mac系统里,每行结尾是
回车
,即\r
.从Mac OS X开始与Linux统一
- Windows系统里,每行结尾是
2.4 字节输出流[InputStream]
java.io.InputStream
抽象类是表示字节输入流的所有类的超类,可以读取字节信息到内存中,他定义了字节输入流的基本共性功能方法
public void close()
:关闭此输入流并释放于此流相关联的任何系统资源public abstract int read
:从输入流读取数据的下一个字节public int read(byte[] b)
:从输入流中读取一些字节数,并将它们储存到字节数组b中
2.5 FileInputStream类
java.io.FileInputStram
类是文件输入流,从文件读取字节
构造方法
FileInputStream(File file)
:通过打开与实际文件的连接来创建一个FileInputStream
,该文件有文件系统中的File对象file命名FileInputStream(String name)
:通过打开与实际文件的连接来创建一个FileInputStream
,该文件由文件系统中的路径名name命名
当你创建一个流对象是,必须传入一个文件路径.该路径下,如果没有该文件,会抛出FileNotFoundException
public class Test1 {
public static void main(String[] args) throws IOException {
// 使用File对象创建流对象
File file = new File("a.txt");
FileInputStream fos = new FileInputStream(file);
// 使用文件名称创建流对象
FileInputStream fos1 = new FileInputStream("b.txt");
}
}
读取字节数据
读取字节 read方法
,每次可以读取一个字节的数据,提升为int类型
,读取到文件末尾,返回-1,
public class Test1 {
public static void main(String[] args) throws IOException {
// 使用文件名称创建流对象
FileInputStream fis = new FileInputStream("read.txt");
// 读取数据,返回一个字节
int read = fis.read();
System.out.println((char) read);
// 关闭资源
fis.close();
}
}
使用字节数组读取:read(byte[] b)
,每次读取b的长度个字节到数组中,返回读取到的字节个数,读取到末尾时,返回-1
public class Test1 {
public static void main(String[] args) throws IOException {
// 使用文件名称创建流对象
FileInputStream fis = new FileInputStream("read.txt");
// 定义变量,作为有效个数
int len;
// 定义字节数组,作为装字节数据的容器
byte[] bytes = new byte[2];
// 循环读取
while (((len = fis.read(bytes)) != -1)) {
// 每次读取后,把数字变成字符串打印
System.out.println(new String(bytes));
}
// 关闭资源
fis.close();
}
}
错误数据d,由于最后一次读取时,只读取一个字节e,数组中方,上次读取的数据没有完全替换,所以要通过Len,获取有效的字节
public class Test1 {
public static void main(String[] args) throws IOException {
// 使用文件名称创建流对象
FileInputStream fis = new FileInputStream("read.txt");
// 定义变量,作为有效个数
int len;
// 定义字节数组,作为装字节数据的容器
byte[] bytes = new byte[2];
// 循环读取
while (((len = fis.read(bytes)) != -1)) {
// 每次读取后,把数组的有效不扽变成字符串打印
System.out.println(new String(bytes,0,len));//len每次读取到的有效字节个数
}
// 关闭资源
fis.close();
}
}
- 使用数组读取,每次读取多个字节,减少系统间IO操作次数,从而提高了读写的效率
3. 字符流
当使用字节流读取文本文件时,可能会有一个小问题,就是遇到中文字符时,可能不会显示完整的字符,那是因为一个中文字符可能占用多个字节存储.所以Java提供了一些字符流类,以字符为单位读写数据,专门用于处理文本文件
3.1 字符输入流[Reader]
java.io.Read
抽象类是表示用于读取字符流的所有超类,可以读取字符信息到内存中.它定义了字符输入流的基本共性功能方法
public void close()
:关闭此流并释放此流相关联的任何系统资源public int read()
:从输入流读取一个字符public int read(char[] cbuf)
:从输入流中读取一些字符,并将它们存储到字符数组cbuf中
FileReader类
java.io.FileReader
类是读取字符文件的便利类.构造时使用系统默认的字符编码和默认字节缓冲区
- 字符编码:字节与字符的对应规则,Windows系统中的中文编码默认是GBK编码表
- 字节缓冲区:一个字节数组,用来临时存储字节数据
构造方法
FileReader(File file)
:创建一个新的FileReader
,给定要读取的File
对象FileReader(String name)
:创建一个新的FileReader
,给定要读取的文件的名称
当你创建一个流对象时,必须传入一个文件路径
public class Test1 {
public static void main(String[] args) throws IOException {
// 使用File对象创建流对象
File file = new File("a.txt");
FileReader fr = new FileReader(file);
// 使用文件名称创建流对象
FileReader fr1 = new FileReader("b.txt");
}
}
读取字符数据
读取字符 read
方法,每次可以读取一个字符的数据,提升为int
类型,读取到文件末尾,返回-1,循环读取
public class Test1 {
public static void main(String[] args) throws IOException {
// 使用文件名称创建流对象
FileReader fr = new FileReader("b.txt");
// 定义变量,保存数据
int b;
// 循环读取
while (((b = fr.read()) != -1)) {
System.out.println((char) b);
}
// 关闭系统资源
fr.close();
}
}
使用字符数组读取:read(char[] cbuf)
,每次读取b的长度个字符到数组中,返回读取到的有效个数,读取到末尾时,返回-1
public class Test1 {
public static void main(String[] args) throws IOException {
// 使用文件名称创建流对象
FileReader fr = new FileReader("b.txt");
// 定义变量,保存有效个数
int len;
//定义字符数组,作为装字符数据的容器
char[] chars = new char[2];
// 循环读取
while (((b = fr.read(chars)) != -1)) {
System.out.println(chars,0,len);
}
// 关闭系统资源
fr.close();
}
}
3.3 字符输出流[Writer]
java.io.Writer
抽象类是表示用于写出字符流的所有类的超类,将指定的字符信息写出到目的地.它定义了字节输出流的基本共性功能方法
void write(int c)
写入单个字符void write(char[] chars)
写入字符数组abstract void write(char[] chars,int off,int len)
写入字符数组的某一部分,off数组的开始索引,len写的字符个数void write(String str)
写入字符串void write(String str,int off,int len)
写入字符串的某一部分,off字符串的开始索引.len写的字符个数void flush()
刷寻此流的缓冲void close()
关闭此流,但要刷新它
3.4 FileWrite类
java.io.FileWriter
类是写出字符到文件的便利类.构造是使用系统默认的字符编码和默认的字节缓冲区
构造方法
FileWriter(File file)
:创建一个新的FileWriter
,给定要哦读取的File
对象FileWriter(String fileName)
:创建一个新的FileWriter
,给定要读取的文件名称
public class Test1 {
public static void main(String[] args) throws IOException {
// 使用File对象创建流对象
File file = new File("a.txt");
FileWriter fw = new FileWriter(file);
// 使用文件名称创建流对象
FileWriter fw = new FileWriter("b.txt");
}
}
基本写出数据
写出字符 write(int b)
方法,每次可以写出一个字符数据
public class Test1 {
public static void main(String[] args) throws IOException {
// 使用文件名称创建流对象
FileWriter fw = new FileWriter("b.txt");
// 写出数据
fw.write(97); // 写出第1个字符
fw.write('b'); // 写出第2个字符
fw.write('c'); // 写出第3个字符
fw.write(30000); // 写出第4个字符,中文编码表中30000对应一个汉字
}
}
- 虽然参数为
int
类型四个字节,但是只会保留一个字符的信息写出 - 未调用
close
方法,数据值保存到了缓冲区,并未写出到文件中
关闭和刷新
因为内置缓冲区的原因,如果不关闭输出流,无法写出字符到文件中.但是关闭的流对象,是无法继续写出数据,如果我们既想写出数据,又想继续使用流,就需要flush方法
flush
:刷新缓冲区,流对象可以继续使用close
:先刷新缓冲区,然后通知系统释放资源,流对象不可以在被调用
public class Test1 {
public static void main(String[] args) throws IOException {
// 使用文件名称创建流对象
FileWriter fw = new FileWriter("b.txt");
// 写出数据,通过flush
fw.write(97); // 写出第1个字符
fw.flush();
fw.write('b'); // 写出第2个字符,写出成功
fw.flush();
// 写出数据,通过close
fw.write('c'); // 写出第1个字符
fw.close();
fw.write(30000); // 继续写出第2个字符,[报错]java.io.IOException:Stream close
fw.close();
}
}
- 即便是flush方法写出了数据,操作的最后还是要调用
close
方法.释放系统资源
写出其他数据
写出字符数组 write(char[] chars)
和write(char[] chars,int off,int len)
,每次可以写出字符数组中的数据
public class Test1 {
public static void main(String[] args) throws IOException {
// 使用文件名称创建流对象
FileWriter fw = new FileWriter("b.txt");
// 字符串转换为字符数组
char[] chars = "我爱你".toCharArray();
//写出字符数组
fw.write(chars);
//从索引2开始,2个字节
fw.write(chars,2,2);
fw.flush();
fw.close();
}
}
写出字符串:write(String str)
和write(String str,int off,int len)
,每次可以写出字符串中的数据,更为方便
public class Test1 {
public static void main(String[] args) throws IOException {
// 使用文件名称创建流对象
FileWriter fw = new FileWriter("b.txt");
// 字符串
String msg = "bsj";
//写出字符床
fw.write(msg);
// 从索引2开始,2个字节
fw.write(msg,2,2);
// 关闭资源
fw.flush();
fw.close();
}
}
续写和换行:
public class Test1 {
public static void main(String[] args) throws IOException {
// 使用文件名称创建流对象
FileWriter fw = new FileWriter("b.txt");
// 写出字符串
fw.write("bsj");
// 写出换行
fw.write("\r\n");
// 写出字符串
fw.write("bsj");
//关闭资源
fw.close();
}
}
- 字符流只能操作文本文件,不能操作图片,视频等非文本文件
- 当我们单纯读或者写文本文件时,使用字符流 其他情况使用字节流
4. 属性集
4.1 概述
java.util.Properties
继承与Hsahtable
,来表示一个持久的属性集,它使用键值结构存储数据,每个键及其对应值都是一个字符串,该类也被许多Java
类使用,比如获取系统属性时,System.getProperties
方法就是返回一个Properties
对象
5.2 Properties类
构造方法
public Properties()
:创建一个空的属性列表
基本的存储方法
public Object setProperty(String key,String value)
:保存一对属性public String getProperty(String key)
:使用此属性列表中指定的键搜索属性值public Set<String> stringPropertyName()
:所有键的名称的集合
public class Test1 {
public static void main(String[] args) throws IOException {
// 创建属性集对象
Properties properties = new Properties();
// 添加键值对元素
properties.setProperty("filename","a.txt");
properties.setProperty("length","2093569856");
properties.setProperty("location","D:\\a.txt");
// 打印属性集对象
System.out.println(properties);
// 通过键,获取属性值
System.out.println(properties.getProperty("filename"));
System.out.println(properties.getProperty("length"));
System.out.println(properties.getProperty("location"));
// 遍历属性集,获取所有键的集合
Set<String> strings = properties.stringPropertyNames();
// 打印键值对
for (String key : strings) {
System.out.println(key+"="+properties.getProperty(key));
}
}
}
与流相关的方法
public void load(InputStream)
:从字节输出流中读取键值对
参数中使用了字节输入流,通过流对象,可以关联到某个文件上,这样就能加载文本中的数据了
public class Test1 {
public static void main(String[] args) throws IOException {
// 创建属性集对象
Properties properties = new Properties();
// 加载文本中信息到属性集
properties.load(new FileInputStream("read.txt"));
// 遍历集合打印
Set<String> strings = properties.stringPropertyNames();
for (String key : strings) {
System.out.println(key+"="+properties.getProperty(key));
}
}
}
- 文本中的数据必须是键值对形式.可以使用空格,等号,冒号等符号分隔