前提
IO流是输入输出流,字符和字节的输入和输出
1.OutputSteam 字节输出流超类
1.1写入数据的原理:
java程序–>JVM–> OS操作系统–>OS调用写数据的方法–>数据写入到文件中
1.2 OutputSteam的成员方法
void close()
关闭此输出流并释放与此流有关的所有系统资源。
void flush()
刷新此输出流并强制写出所有缓冲的输出字节。
void write(byte[] b)
将 b.length 个字节从指定的 byte 数组写入此输出流。
void write(byte[] b, int off, int len)
将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。 左闭右开区间,或者说是个数
abstract void write(int b)
将指定的字节写入此输出流。
2 . FileOutputStream 文件输出流 java.util.FileOutputStream extends OutputSteam
2.1构造方法
FileOutputStream(String name)
创建一个向具有指定名称的文件中写入数据的输出文件流
FileOutputStream(File file)
创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
解释:String name是一个文件的路径
File file 目的地是一个文件
构造方法作用:
1,创建一个FileOutputStream对象,根据构造方法的中传递的文件/文件路径,创建一个空文件
2.把该对象指向创建好的文件
2.2字节输出流使用步骤
1.创建FileOutputStream 对象,噶偶早方法床底写入数据的目的地
2.调用FileOutputStream方法write写入数据进文件
3,释放资源
下面举个例子
public static void main(String[] args) throws IOException {
// 1.创建FileOutputStream 对象,构造方法写入数据的目的地
FileOutputStream f = new FileOutputStream("E:\\a.txt");
// 2.调用FileOutputStream方法write写入数据进文件
f.write(97);
// 3,释放资源
f.close();
}
2.3文件存储的原理
硬盘中存储的是字节,当打开的时候,根据ASCII等编码表转化为相应的字符
2.4.一次写多个字节的方法
OutputSteam的成员方法:
void write(byte[ ] b)
将 b.length 个字节从指定的 byte 数组写入此输出流。
void write(byte[ ] b, int off, int len)
将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。
package IO;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class IOtest1 {
public static void main(String[] args) throws IOException {
//ASCll 0-->48
// void write(byte[ ] b)
// 将 b.length 个字节从指定的 byte 数组写入此输出流。
//输入100
FileOutputStream fileOutputStream=new FileOutputStream(new File("E:\\b.txt"));
fileOutputStream.write(49);
fileOutputStream.write(48);
fileOutputStream.write(48);
//void write(byte[ ] b, int off, int len)
// 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。
//len:写几个字节
//off:索引值
byte[] b= {-65,-66,-67,68,69};
//如果第一个字节是正数,则显示查询ASCII表
//如果第一个字节负数,第一和第二个字节组成一个中文,查询GBK
fileOutputStream.write(b,1,2);
fileOutputStream.close();
}
}
2.5.追加和续写字符
FileOutputStream(File file, boolean append)
创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
FileOutputStream(String name, boolean append)
创建一个向具有指定 name 的文件中写入数据的输出文件流。
// boolean append 追加开关 true 创建对象不覆盖源文件,false创建一个新文件,覆盖源文件
// String name,File file 写入数据目的地
package IO;
import java.io.FileOutputStream;
import java.io.IOException;
public class IOtest2 {
public static void main(String[] args) throws IOException {
//创建对象
FileOutputStream f=new FileOutputStream("E:\\c.txt",true);
for (int i = 0; i < 10; i++) {
f.write("你好啊".getBytes());
//换行
f.write("\n\r".getBytes());
}
}
}
3.InputStream 字节输入流超类
3.1子类共性方法:
int read()
从此输入流中读取一个数据字节。
int read(byte[] b)
从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。
void close()
3.2 FileInputStream java.util.FileInputStream extends InputStream
构造方法:
FileInputStream(File file)
FileInputStream(String name)
构造方法作用: 创建对象,读取文件
3.3 int read()
从此输入流中读取一个数据字节。
import java.io.FileInputStream;
import java.io.IOException;
public class IOtest2 {
public static void main(String[] args) throws IOException {
// int read()
//从此输入流中读取一个数据字节。
//一次读取一个字节 ,指针往后一位,下一次读的是下一位
FileInputStream f=new FileInputStream("E:\\a.txt");
int len=0;
while( len!=-1)
{
len= f.read();
if(len==-1)break;
System.out.println(len);
}
}
}
总结:一次读取一个字节 ,读完指针往后一位,下一次读的是下一位。
3.4一次读取多个字符的方法
int read(byte [ ] b,int offset,int length) 读取一定数量字节,存在缓冲区b中
offset:开始的索引值
length:个数
注意:
1.数组的长度一般定义为1024
2.方法返回的int是有效字节个数
3.读取中文 GBK2个字节,UTF-8 3个字节
比如说文件里有 【A,B,C,D,E】第一次读AB ,二次CD,三次ED,第三次 E就把C覆盖了。
package IO;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class IOtest2 {
public static void main(String[] args) throws IOException {
//a.txt ABCDE
InputStream inputStream=new FileInputStream("E:\\a.txt");
//创建数组
byte[] bytes=new byte[2];
//遍历
//定义有效的字符串的个数
int result=0;
while(result!=-1)
{
result= inputStream.read(bytes,0,2);
if(result==-1) break;
System.out.println(result);
System.out.println(new String(bytes));
/*
2
AB
2
CD
1
ED */
}
}
}
总结:String的构造方法new String(byte数组名)可以直接输出 byte中的真实字段
4.Reader抽象类 字符输入流的超类
用于读取字符流的抽象类
4.1 常见成员方法
int read()
读取单个字符。
int read(char[ ] cbuf)
将字符读入数组。
abstract int read(char[] cbuf, int off, int len)
将字符读入数组的某一部分。
abstract void close()
关闭该流并释放与之关联的所有资源。
4.2FileReader 文件字符输入流 FileReader extendsFileInputStream
构造方法:
FileReader(File file)
在给定从中读取数据的 File 的情况下创建一个新 FileReader对象。
FileReader(String fileName)
在给定从中读取数据的文件名的情况下创建一个新 FileReader对象r。
参数:filename文件路径 file文件名
使用构造:创建对象,传入文件名或者路径
import java.io.FileReader;
import java.io.IOException;
public class test1 {
public static void main(String[] args) throws IOException {
//循环读取所有字符
FileReader fileReader=new FileReader("E:\\a.txt");
int len;
while((len=fileReader.read())!=-1) {
System.out.println((char)len);
}
//String的构造方法读取部分字符
char[] chars=new char[1024];
FileReader fileReader1=new FileReader("E:\\a.txt");
while((fileReader1.read(chars))!=-1)
{
//String构造方法,将char数组一部分转换为字符串
//public String(char value[], int offset, int count)
// public String(char value[] 将char数组转换为字符串
System.out.println(new String(chars,0,3));
}
}
}
5.字符输出流 Writer超类
所有字节输出流的父类
5.1FileWriter FileWriter extends OutputStreamWriter extends Writer
构造方法:
FileWriter(File file)
在给定从中读取数据的 File 的情况下创建一个新 FileWrite对象r。
FileWriter(String fileName)
在给定从中读取数据的文件名的情况下创建一个新 FileWriterd对象。
参数:filename文件路径 file文件名
使用构造:创建对象,传入文件名或者路径,没文件就创建文件,对象指向创建好的文件
5.1.1 字符输出流使用步骤:
1.创建FileWriter对象
2.使用FileWrite方法write,把数据写入内存缓冲区(字符转换为字节)
3.使用FileWriter方法flush把内存缓冲区数据刷新到文件中
4.释放资源
注意:close和flush都可以刷新缓冲区
最好用flush刷新缓冲区,不用close,因为close后就不可以使用流对象了
import java.io.FileWriter;
import java.io.IOException;
public class wirtertest {
public static void main(String[] args) throws IOException {
FileWriter fileWriter=new FileWriter("d.txt");
fileWriter.write(99);
fileWriter.flush(); //刷新
fileWriter.close(); //刷新后结束
}
}
5.1.2字符输出流数据的其他方法
void write(char[] cbuf)
写入字符数组。
abstract void write(char[] cbuf, int off, int len)
写入字符数组的某一部分。
void write(String str)
写入字符串。
void write(String str, int off, int len)
写入字符串的某一部分。
import java.io.FileWriter;
import java.io.IOException;
public class wirtertest {
public static void main(String[] args) throws IOException {
FileWriter fileWriter=new FileWriter("f.txt");
// 1. void write(char[] cbuf)
// 写入字符数组。
// abstract void write(char[] cbuf, int off, int len)
// 写入字符数组的某一部分。
char[ ]chars= {'a','5','9','F'};
fileWriter.write(chars,0,3);
fileWriter.flush();
//2.void write(String str) 写入字符串。
// void write(String str, int off, int len) 写入字符串的某一部分。
FileWriter fileWriter1=new FileWriter("g.txt");
String str="hjaksdh";
fileWriter1.write(str,0,4);
fileWriter1.flush();
}
}
5.2 字符输出流的续写和换行
就是在文件名逗号一个,append
5.3用try catch来处理流异常
在JDK7之前
我们这样处理
字符输出流的异常处理
1,close关闭资源的时候要trycatch
2.字符输出流对象,要在try catch外定义对象,在try catch里面使用
//定义对象为空
FileWriter fw=null;
//产生异常的代码
try
{
fw=new FileWriter("d.txt",true);
for (int i = 0; i < 10; i++)
{
fw.write("Hello world"+"\n\r");
}
}
catch (IOException e)
{
System.out.println("IO异常");
}
finally
{
//这可能会出现空指针异常
if(fw!=null)
{
try
{
fw.close();
} catch (IOException e)
{
e.printStackTrace();
}
}
}
}
}
是不是吐了…来个好用的
JDK7新特性:
1.在try后边可以加一个括号,在括号里面可以定义流对象。所以这个流对象在try中有效,就不用在try外面定义了
2.try中的代码执行完毕会自动释放流对象,不用finally
简化之后
mport java.io.FileWriter;
import java.io.IOException;
public class test2 {
public static void main(String[] args) {
try( FileWriter fw=new FileWriter("d.txt",true);)
{
//执行的代码写这里
fw.flush();
} catch (IOException e) {
e.printStackTrace();
}
//结束后自动关闭流对象
}
}
6.Properties集合(唯一个与IO流相关的集合)
Properties集合继承了Hashtable。 Hashtable<K,V> implements Map<K,V>
介绍:
Properties 类表示了一个持久的属性集。Properties 可保存在流中或从流中加载
。属性列表中每个键及其对应值都是一个字符串。
Properties集合是一个双列集合,key和value默认都是字符串
成员方法:
- stote: 把集合中临时数据,放入硬盘存储
1.1 OutputStream out字节输出流:不能使用中文。
Writer w :字符输出流,可以写中文
1.2. String comments 注释:用来解释说明保存的文件是做什么的,不能使用中文,默认Unicode,一般使用空字符串
1.3,使用步骤:
1.创建Properties集合,添加数据
2.创建流对象,并传输文件地址
3.使用store方法,存储数据到地址中
4.释放资源
public static void show1() throws IOException {
//1.创建properties集合对象
Properties p=new Properties();
p.setProperty("我","18");
p.setProperty("你","19");
p.setProperty("他","20");
//2.创建字符输出流
FileWriter f=new FileWriter("g.txt");
//3.使用store方法
p.store(f,"Save data");
//4.释放资源
f.close();
}
-
load:把硬盘中的文件(键值对)读取到集合当中使用
从输入流中读取属性列表(键和元素对) void load(InputStream inStream) void load(Reader reader)
2.1 注意:
InputStream input字节输入流,不能读取含有中文的键值对
Reader reader 字符输入流,能读取有中文的键值对
2.2 注意:
在存储键值对文件中
1.键与值默认连接符号可以使用=,(空格)其他符号
2.可以使用#进行注释,备注的键值对不会被读取
3.键与值类型默认字符串,不用加引号
2.3 使用方法:
1.创建Properties集合
2.使用方法load读取(保存有键值对)文件
3.用Set集合遍历Properties集合
public static void show2() throws IOException {
//1.创建properties对象
Properties pp=new Properties();
//2.使用load方法读取键值对
pp.load(new FileReader("g.txt"));
// 3.用set循环遍历
Set<String> set=pp.stringPropertyNames();
for( String key:set)
{
System.out.println(pp.getProperty(key));
}
}
-
Object setProperty(String key, String value),调用Hashtable 的方法 put。
-
Set set=Properties对象.stringPropertyNames()
返回此属性列表中的键集合,其中键值对应的都是字符串
相当于Map集合中的Keyset() -
String getProperty(String key),通过K获得value
相当于get(key)方法
public static void show3()
{
//创建对象
Properties p=new Properties();
//3. Object setProperty(String key, String value),调用Hashtable 的方法 put。
p.setProperty("我","18");
p.setProperty("你","19");
p.setProperty("他","20");
//4.Set<String> set=Properties对象.stringPropertyNames()()
Set<String> set=p.stringPropertyNames();
for(String key:set)
{
// 5.String getProperty(String key),通过K获得value
String value=p.getProperty(key);
System.out.println("key"+key);
}
}
7.缓冲流 BufferedXxxStream java.io.BufferedXxxStream extends FilterXxxStream
构造方法:BufferedXxx(Xxxr out)
创建一个使用默认大小输出缓冲区的缓冲字符输出流。
BufferedXxx(Xxxr out, int sz)
创建一个使用给定大小输出缓冲区的新缓冲字符输出流。
Xxx是流 ,Xxxr是流对象,sz是缓冲区大小,不写默认8192Byte
7.1
使用步骤:
1.创建FileXxxStream 流对象,输入文件目的地 字节输入和输出流各创建一个
2.创建BufferedXxxStream 对象,构造方法中传递FileXxxStream对象 字节输入和输出流各创建一个
- 使用BufferedXxxStream类的read方法读取文件 字节输入流
使用BufferedXxxStream类的write方法写入文件到缓冲区 字节输出流
(可以用Byte数组记录每一个返回的有效字节)
4.使用BufferedXxxStream类的 flush方法把内部缓冲区的文件,刷新到文件中。
5.close(会调用flush方法),第四步可以省略.
//1
FileOutputStream f=new FileOutputStream("h.txt");
//2
BufferedOutputStream b=new BufferedOutputStream(f);
//3
b.write("我把数据写入内部缓冲区中".getBytes());
//4
b.flush();
b.close();
7.2效率测试 使用缓冲流方法,四种流都一样的
将一个图片从C盘复制到D盘
//一读一写计算时间
//计时开始
long start=System.currentTimeMillis();
//1. 创建字节输入流对象,放入源地址
FileInputStream f=new FileInputStream("C:\\1.jpg");
//2.创建字节输出流对象,放入目的地址
FileOutputStream f1=new FileOutputStream("D:\\1.jpg");
//3.创建字节缓冲输入流,并放入相应流的对象
BufferedInputStream b=new BufferedInputStream(f);
//4.创建字节缓冲输出流,并放入相应流的对象
BufferedOutputStream b1=new BufferedOutputStream(f1);
//5.读取并写入缓冲区,创建一个字节数组来接收读取和写入的有效字节
byte[] bytes=new byte[1024];
int len=0;
while ((len=b.read(bytes))!=-1) //每读取一个有效字节就放入数组中
{
b1.write(bytes,0,len); //把数组每次读取的有效个数写入缓冲区
}
b.close();
b1.close();
//结束计时
long end=System.currentTimeMillis();
System.out.println("复制文件花费了"+(end-start)+"ms");
7.3字符缓冲流输出流 BufferedWriter BufferedWriterStream extends Writer类
构造方法:
BufferedWriter(Writer out)
创建一个使用默认大小输出缓冲区的缓冲字符输出流。
BufferedWriter(Writer out, int sz)
创建一个使用给定大小输出缓冲区的新缓冲字符输出流。
补充:
字符缓冲输出流特有成员方法:
换行:
BufferedWriterStream 对象.newLine
注意:写在Writer后面,写完就换行
这个的底层就是换行:
System.out.println()
7.4字符缓冲输入流 BufferedReader BufferedReaderStream extends Reader类**
构造方法:
BufferedReader(Reader in)
创建一个使用默认大小输入缓冲区的缓冲字符输入流。
BufferedReader(Reader in, int sz)
创建一个使用指定大小输入缓冲区的缓冲字符输入流。
补充:
字符缓冲输入流特有成员方法:
String readLine()
读取一个文本行。
返回:包含该行内容的字符串,不包含任何行终止符
注意:
读取一行后如再读取则读下一行,读取NULL的时候结束
FileReader f=new FileReader("c.txt");
BufferedReader b=new BufferedReader(f);
//循环遍历输入
String line;
while ((line =b.readLine())!=null)
{
System.out.println(line);
}
8.转换流
8.1字符编码和字符集
编码:字符–>字节
解码:字节–>字符
字符编码:一套自然语言的字符与二进制之间对应规则
编码表:文字与二进制对应规则
ASCII编码–> 必须ASCII解码,否则乱码
字符集: charset
ASCII编码表:英文
GBK:中文码表 3个字节
UTF-8 如果储存中文 3 个字节
Unicode存储世界所有国家文字,符号。四个字节
web开发UTF-8
8.2FileReader的read方法读取规则
FileReader可以读取IO默认编码格式UTF-8的格式
FileReader读取系统默认编码GBK会产生乱码
8.3 OutputStreamwirter OutputStreamwriter extends Writer
OutputStream是字符转换为字节的桥梁,可以指定charset 这个是编码,把看懂的—>变成看不懂的
构造方法:
OutputStreamWriter(OutputStream out)
创建使用默认字符编码的 OutputStreamWriter
OutputStreamWriter(OutputStream out, String charsetName)
创建使用指定字符集的 OutputStreamWriter。
OutputStream out:字节输出流,可以把转换后的字节写入文件中
charsetName:指定编码表,不区分大小写。UTF-8/utf-8
使用步骤:
1.创建对象,构造方法中传递字节输出流FileoutputStream对象和指定编码名称
2.使用OutputStreamWriter中的write方法,把字符转换为字节存储在缓冲区
3.使用OutputStreamWriter中的flush方法,刷新到缓冲区
4.释放资源
//1 OutputStreamWriter o=new OutputStreamWriter(new FileOutputStream("c.txt"),"GBK");
//2
o.write("你好");
//3
o.flush();
//4
o.close();
8.4InputStreamReader java.io.InputStreamReader
InputStreamReader是字节–>字符的桥梁 这是解码,把看不懂的变成看的懂得
构造方法:
InputStreamReader(InputStream in)
创建一个使用默认字符集的 InputStreamReader。
InputStreamReader(InputStream in, String charsetName)
创建使用指定字符集的 InputStreamReader。
**注意:构造方法中指定的编码和文件的编码要相同 ,否则会乱码 **
使用方法:
1.创建对象,构造方法中传递字节输入流FileInputStream对象和指定编码名称
2.使用InputStreamReaderr中的read方法,读取文件
3,.释放资源
//1
InputStreamReader r=new InputStreamReader(new FileInputStream("c.txt"));
//2
int len=0; //定义返回字节有效的个数
while ((len=r.read())!=-1)
{
System.out.println((char)len); //将字节强转成字符
}
//3
r.close();
将GBK的源文件文件转化为UTF-8
1.创建InputStreamReader的对象传递InputStream的字节输入流源文件和指定表名称编码GBK
2.创建OutputStreamWriter的对象中传递OutputStream的目标文件,并指定编码表名称为UTF-8
3.用InputStreamReader的 read()方法读源文件
4.用OutputStreamWriter对象中的方法write(),把读取的文件写入目标文件中
5.释放资源
//1
InputStreamReader r=new InputStreamReader(new FileInputStream("c.txt"),"GBK");
//2
OutputStreamWriter o=new OutputStreamWriter(new FileOutputStream("d.txt"),"UTF-8");
//3
//遍历写入
int len=0;
while ((len=r.read())!=-1)
{
o.write(len);
}
//4
r.close();
o.close();
.
**9.序列化流 ** 存对象和取对象
序列化:把对象以流的形式写入文件中保存
反序列化 ;把对象以流的形式读取出来
注意:
1.序列化和反序列化的时候,要想让类可以通过流的方法传递,需要打上标记
让作为流的类实现Serializable接口
2.反序列除了实现Serializable接口,还要存在类相对应的class文件,否则就抛出ClassNotFoundException
9.1ObjectOutputStream 对象序列化流(输出流) java.io.ObjectOutputStream extends OutputStream
9.1.1 构造方法:
ObjectOutputStream(OutputStream out)
创建写入指定 OutputStream 的 ObjectOutputStream。
特有的成员方法
void writeObject(Object obj)
将指定的对象写入 ObjectOutputStream。
9.1.2 使用说明:
1.创建ObjectOutputStream对象,构造方法中传递字节输出流
2.使用ObjectOutputStream方法writeObject,把作为流的类的对象写入文件中
3.释放资源
//Person已经实现Serializable
public static void main(String[] args) throws IOException {
//1
ObjectOutputStream o=new ObjectOutputStream(new FileOutputStream("g.txt"));
//2
o.writeObject(new Person("我",18));
//3
o.close();
9.2 ObjectInputStream 对象反序列化 (输入流) java.io.ObjectInputStream extends InputStream
作用:把文件中保存的对象,以流的形式读取出来
构造方法:
ObjectInputStream(InputStream in)
创建从指定 InputStream 读取的 ObjectInputStream。
特有成员方法:
Object readObject()
从 ObjectInputStream 读取对象
使用说明:
1.创建ObjectInputStream对象,构造方法中传递字节输入流
2.使用ObjectInputStream方法readObject,读取保存对象的文件
3.释放资源
4.打印
注意:反序列除了实现Serializable接口,还要存在类相对应的class文件,否则就抛出ClassNotFoundException
//1
ObjectInputStream o=new ObjectInputStream(new FileInputStream("g.txt"));
//2
Object r=o.readObject();
//3
o.close();
//4
System.out.println(r);
9.3 transient关键字,放序列化(这个效果和static一样)
static:static修饰的关键字优先载入JVM内存中
transient关键字可以使成员变量不能序列化
当你有部分变量不想序列化的时候,就使用这个关键字
9.4序列和反序列的注意事项
在每一个作为流的类里面都加上一个UID
static final long serialVersionUID =一段数字 L
private static final long serialVersionUID=4354L;
pirvate是声明是这个类才能用的。
10 打印流 PrintStream PrintStream extends OutputStream java.io.PrintStream
10.1 特点:
1.永远不会抛出IOexception
2.只负责数据的输出
3.有特有方法print和println
构造方法:
PrintStream(File file) 输出的目的地是一个文件
PrintStream(OutputStream out)输出的目的地是一个字节输出流
PrintStream(String fileName)输出的目的地是一个文件路径
特有方法
print和println
10.2 注意:
如果使用继承自父类的write方法写数据,那么查看数据就会查询编码表 97–>a
如果使用print和println就是97–>97
PrintStream ps=new PrintStream("c.txt");
ps.write(97); //a
System.out.println(97); //97
10.3改变输出语句的目的地
修改输出的位置,比如说:在控制台输出的改成在某个文件里输出
输出语句默认在控制台输出
使用System.setOut() 目的地从控制台改为 PrintStream的构造方法中传递的那个文件名
使用步骤:
1.创建PrintSteam对象,传入文件名
2.调用System.setOut()方法,将PrintSteam对象传进去
下面是实现
public class test9 {
public static void main(String[] args) throws FileNotFoundException {
System.out.println("123456"); //控制台123456
PrintStream ps=new PrintStream("c.txt");
System.setOut(ps);
System.out.println("654321"); //在c.txt里输出
}
}
PrintStream 用法
https://blog.csdn.net/u013087513/article/details/51981306