I/O流

主要内容

java.io.File类的使用---就是计算机操作系统中的文件和文件夹

 

1.什么是IO流?

I/O即输入input和输出Output的缩写,就是计算机调度把各个存储中的数据写入写出的过程

通过程序把图片放到一个文件夹中,其实就是把图片转换为一个数据集(例如:二进制),把这些数据一点点传输到文件夹,这个传递的过程就类似于水的流动,这样的一整个过程就称为数据流

java中用"流"来抽象表示这么一个写入写出的功能,封装成一个类。放在java.io这个包中

File类 文件流 数据流的读写都是基于文件的操作

file类只能操作文件本身,不能操作文件中的内容;就类似于你有一个本子,你可以任意调整它的位置

却不能改变它里面的内容

FileInputStream/FileOutputStream/FileReader/FileWriter

Buffered缓冲流 数据流的读写都是基于内存的操作

BufferedInputStream/BufferedOutputStream/BuffereadReader/BuffereadWriter

注:IO操作都是有异常的

 

2.流大致分

  • 按照数据单位的不同分为:字节流(8bt),字符流(16bt)。
    按照数据流的流向不同分为:输入流和输出流
    按照角色的不同分为:节点流,处理流
  • 按照操作流的数据单位不同,分为字节流和字符流。字节流按一个字节或多个字节数据读写,当传输的资源文件有中文时,就会出现乱码。;字符流按一个字符或多个字符进行读写
    1字符 = 2字节; 1字节(byte) = 8位(bit); 一个汉字占两个字节长度。
  • 输入流和输出流
    按照流传输方向的不同,分为输入流和输出流
  • 节点流和处理流
    按流的功能不同,分为节点流和处理流。节点流又称低级流,值只能直接连接数据源进行读写操作。处理流又称高级流,指对已经存在的节点流连接、分装,通过封装后的流进行读写操作。处理流不会直接连接数据源

 

3.我们在使用的时候应该怎么选择呢?比如什么时候用输出流?什么时候用字节流?可以根据下面三步选择适合自己的流:

  • 首先自己要知道是选择输入流还是输出流。这就要根据自己的情况决定,如果想从程序写东西到别的地方,那么就选择输入流,反之就选输出流;
  • 然后考虑你传输数据时,是每次传一个字节还是两个字节,每次传输一个字节就选字节流,如果存在中文,那肯定就要选字符流了。
  • 通过前面两步就可以选出一个合适的节点流了,比如字节输入流 InputStream,如果要在此基础上增强功能,那么就在处理流中选择一个合适的即可

 

 

 

 

Java IO原理

IO流用来处理设备之间的数据传输

 

java程序中,对于数据的输入/输出操作以"流(stream)"的方式进行。

 

java.io包下提供了各种"流"的类和接口,用以获取不同类型的数据,并通过标准的方法输入或输出数据

 

注意:不论输入还是输出,都是指计算机

输入input:读取外部数据(磁盘、光盘等存储数据)到程序的(内存)中。

输出output:将程序(内存)数据,输出到磁盘、光盘等存储设备中

 

 

 

 

字节流

I/O流中针对字节的输入和输出提供了字节流。字节流按传输方向分为字节输入流和字节输出流。字节流的顶级父类:InputStream(输入-读)和OutputStream(输出-写)。这两个类都是抽象类,无法实例化

 

( =1).字节输入InputStream

常用方法

  • int read():从输入流中读取一个字节的二进制数据。
  • int read(byte[] b):将多个字节读到数组中,填满整个数组。
  • int read(byte[] b, int off, int len):从输入流中读取长度为 len 的数据,从数组 b 中下标为 off 的位置开始放置读入的数据,读完返回读取的字节数。
  • void close():关闭数据流。
  • int available():返回目前可以从数据流中读取的字节数(但实际的读操作所读得的字节数可能大于该返回值)。
  • long skip(long l):跳过数据流中指定数量的字节不读取,返回值表示实际跳过的字节数。

对数据流中字节的读取通常是按从头到尾顺序进行的,如果需要以反方向读取,则需要使用回推(Push Back)操作。在支持回推操作的数据流中经常用到如下几个方法:

  • boolean markSupported():用于测试数据流是否支持回推操作,当一个数据流支持 mark() 和 reset() 方法时,返回 true,否则返回 false。
  • void mark(int readlimit):用于标记数据流的当前位置,并划出一个缓冲区,其大小至少为指定参数的大小。
  • void reset():将输入流重新定位到对此流最后调用 mark() 方法时的位置。
     

字节输入流有很多子类,经常使用的一些类见下

  • ByteArrayInputStream:字节数组输入流,该类的功能就是从字节数组 byte[] 中进行以字节为单位的读取,也就是将资源文件都以字节形式存入到该类中的字节数组中去,我们拿数据也是从这个字节数组中拿。
  • PipedInputStream:管道字节输入流,它和 PipedOutputStream 一起使用,能实现多线程间的管道通信。
  • FilterInputStream:装饰者模式中充当装饰者的角色,具体的装饰者都要继承它,所以在该类的子类下都是用来装饰别的流的,也就是处理类。
  • BufferedInputStream:缓冲流,对处理流进行装饰、增强,内部会有一个缓冲区,用来存放字节,每次都是将缓冲区存满然后发送,而不是一个字节或两个字节这样发送,效率更高。
  • DataInputStream:数据输入流,用来装饰其他输入流,它允许通过数据流来读写Java基本类型。
  • FileInputStream:文件输入流,通常用于对文件进行读取操作。
  • File:对指定目录的文件进行操作。
  • ObjectInputStream:对象输入流,用来提供对“基本数据或对象”的持久存储。通俗点讲,就是能直接传输Java对象(序列化、反序列化用)。

 

(2).字节输出流 OutputStream

与字节输入流类似,http://java.io 包下所有字节输出流大多是从抽象类 OutputStream 继承而来的。OutputStream 提供的主要数据操作方法:

  • void write(int i):将字节 i 写入到数据流中,它只输出所读入参数的最低 8 位,该方法是抽象方法,需要在其输出流子类中加以实现,然后才能使用。
  • void write(byte[] b):将数组 b 中的全部 b.length 个字节写入数据流。
  • void write(byte[] b, int off, int len):将数组 b 中从下标 off 开始的 len 个字节写入数据流。元素 b[off] 是此操作写入的第一个字节,b[off + len - 1] 是此操作写入的最后一个字节。
  • void close():关闭输出流。
  • void flush():刷新此输出流并强制写出所有缓冲的输出字节。

 

 

字符流

从JDK1.1开始,http://java.io 包中加入了专门用于字符流处理的类,它们是以Reader和Writer为基础派生的一系列类。

同其他程序设计语言使用ASCII字符集不同,Java使用Unicode字符集来表示字符串和字符。ASCII字符集以一个字节(8bit)表示一个字符,可以认为一个字符就是一个字节(byte)。但Java使用的Unicode是一种大字符集,用两个字节(16bit)来表示一个字符,这时字节与字符就不再相同。为了实现与其他程序语言及不同平台的交互,Java提供一种新的数据流处理方案,称作读者(Reader)和写者(Writer)。

 

(1)字符输入流

Reader是所有的输入字符流的父类,它是一个抽象类

  • CharReader和SringReader是两种基本的介质流,它们分别将Char数组、String中读取数据。
  • PipedReader 是从与其它线程共用的管道中读取数据。
  • BufferedReader很明显是一个装饰器,它和其他子类负责装饰其他Reader对象。
  • FilterReader是所有自定义具体装饰流的父类,其子类PushBackReader对Reader对象进行装饰,会增加一个行号。
  • InputStreamReader是其中最重要的一个,用来在字节输入流和字符输入流之间作为中介,可以将字节输入流转换为字符输入流。FileReader 可以说是一个达到此功能、常用的工具类,在其源代码中明显使用了将FileInputStream 转变为Reader 的方法。

Reader 中各个类的用途和使用方法基本和InputStream 中的类使用一致。

 

(2)字符输出流

Writer是所有的输出字符流的父类,它是一个抽象类。

  • CharWriter、StringWriter 是两种基本的介质流,它们分别向Char 数组、String 中写入数据。
  • PipedWriter 是向与其它线程共用的管道中写入数据。
  • BufferedWriter 是一个装饰器为Writer 提供缓冲功能。
  • PrintWriter 和PrintStream 极其类似,功能和使用也非常相似。
  • OutputStreamWriter是其中最重要的一个,用来在字节输出流和字符输出流之间作为中介,可以将字节输出流转换为字符输出流。FileWriter 可以说是一个达到此功能、常用的工具类,在其源代码中明显使用了将OutputStream转变为Writer 的方法。

Writer 中各个类的用途和使用方法基本和OutputStream 中的类使用一致。

 

3.缓冲流

  • 作用:为了提高数据读写速度,在JAVA API提供了带缓冲功能的流类。
  • 根据数据操作单位可以把缓冲流分为:
    BufferedInPutStream和BufferedOutPutStream
    BufferedReader和BufferedWriter

 

缓冲流要"套接"在相应的节点流之上,对读和写的数据提供了缓冲功能,提高效率,同时添加了一些新方法。

注:缓冲流是把数据缓冲到内存中

实例

/*
缓冲字节输入流  BufferedInputStream
*/
public void BufferedInputStream() throws Exception {
//文件字节流输入对象
FileInputStream in = new FileInputStream("D:\\AU作品\\基础语法\\src\\com\\IO\\Buffered\\tt.txt");
//缓冲字节流输入对象. 这里文件字节输入流放到缓冲字节输入流
BufferedInputStream bt = new BufferedInputStream(in);
byte[]b=new byte[100];
int len=0;
while((len=bt.read(b))!=-1){
System.out.println(new String(b,0,len));
}
//关闭流的要点:最晚用的最先关
bt.close();
in.close();
}
/*
缓冲字节输出流  BufferedOutputStream
*/
public void BufferedOutputStream() throws Exception {
//创建字节输出流对象
FileOutputStream fs = new FileOutputStream("D:\\AU作品\\基础语法\\src\\com\\IO\\Buffered\\cnm.txt");
//缓冲一下
BufferedOutputStream bo = new BufferedOutputStream(fs);
String st="休息一会";
bo.write(st.getBytes());//写道内存中
bo.flush();//刷到硬盘中
//关闭同上,先用后关。
bo.close();
fs.close();
}
/*
缓冲字节流拷贝文件
*/
xxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxx
//缓冲输入流
BufferedInputStream bft = new BufferedInputStream(f1);
//缓冲输出流
BufferedOutputStream bfs = new BufferedOutputStream(fw);
byte [] t=new byte[100];
int len=0;
while((len=bft.read(t))!=-1){
bfs.write(t,0,len);
}


 

 

4.转换流

转换流提供了在字节字符流之间 的转换。

Java ApI中提供了两个转换流

InputStreamReader和OutputStreamWrite

转换的作用?

字节流中的数据都是字符时,转换为字符流操作更高效。

构造方法:

InputStreamReader( InputStream in)

public InputStreamReader(InputStream in,String charsetName)

例如:Reader red=new InputStreamReader(System.in,"编码类型")//参数1是字节流,参数二是编码类型

一些实例

/*
转换字节输入流为字符输入流  InputStreamReader
*/
public void InputStreamReader() throws Exception{
FileInputStream f1 = new FileInputStream("D:\\基础语法\\src\\com\\IO\\InOut\\tt.txt");
//参数1是字节流,参数二是编码类型
InputStreamReader is = new InputStreamReader(f1, "GBK");
char[] c=new char[100];
int len=0;
while ((len=is.read(c))!=-1){
System.out.println(new String(c,0,len));
}
is.close();
f1.close();
}
/*
转换 字节输出流为字符输出流
注意:在转换字符流的时候,设置的字符集编码要和读取的文件的数据的编码一致,不然就会出现乱码
*/
public void OutStreamWriter()throws Exception{
FileOutputStream f2 = new FileOutputStream("D:\\基础语法\\src\\com\\IO\\InOut\\66.txt");
OutputStreamWriter ot = new OutputStreamWriter(f2, "UTF-8");
ot.write("一定要实践,要练习,要解码");
ot.flush();
ot.close();
f2.close();
}


 

 

 

5.标准输入输出流

System.in和System.out分别代表了系统标准输入和输出设备

默认输入设备是键盘,输出设备是屏幕

System.in的类型是InputStream

System.out的类型是PrintStream,它是OutputStream的子类FileOutputStram的子类

实例

/*
标准输入输出流
*/
public void SystemIn() throws IOException {
//创建一个接受键盘输入数据的输入流
InputStreamReader reader=new InputStreamReader(System.in);
//把输入流放到缓冲流中
BufferedReader bt=new BufferedReader(reader);
String str="";//定义一个临时接受数据的字符串
while ((str=bt.readLine())!=null){
System.out.println(str);
}
bt.close();
reader.close();
}
/*
把控制台输入的内容写到指定的txt文件中 ,当接受到over时,就结束程序。
*/
public void  write2Txt() throws IOException {
InputStreamReader it = new InputStreamReader(System.in);
BufferedReader rt=new BufferedReader(it);
BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\基础语法\\src\\com\\IO\\SystemIn\\123.txt"));
String s="";
while ((s=rt.readLine())!=null){
//如果s输入了over,那么就停止程序,并输出内容
if (s.equals("over")){
break;
}
bw.write(s);
}
bw.flush();
bw.close();
rt.close();
it.close();
}


 

6.数据流

为了方便操作java语言基本的数据类型的数据,可以使用数据流

数据流有两个类

  1. 用于读取基本类型的:DataInputStream
  2. 用于写出基本类型的:DataOutputStream

分别"套接"在InputStream和OutputStream节点流上

DataInputStream中的一些方法

char readChar() byte readByte()

double readDouble() float readFloat()

long readLong() int readInt()

String readUTF()

DataOutputStream中的方法,把上方的read改成write就行

实例

/*
DataOutStream
数据输出流
用数据输出流写道文件中的基本数据,是乱码的,不能直接辨认出来,需要数据输入流来获取
*/
public void testDataOutputStream()throws Exception{
DataOutputStream ds = new DataOutputStream(new FileOutputStream("D:\\AU作品\\基础语法\\src\\com\\IO\\Data\\fs.txt"));
//ds.writeInt(11);
//ds.write(100);
//ds.writeBoolean(true);
ds.writeDouble(20.9);
ds.close();
}
/*
用数据输出流写道文件中的基本数据,是乱码的,不能直接辨认出来,需要数据输入流来获取
读取时,要保证和写的类型一致。
*/
public void testDataInputStream()throws Exception{
DataInputStream din = new DataInputStream(new FileInputStream("D:\\AU作品\\基础语法\\src\\com\\IO\\Data\\fs.txt"));
//比如这里因为上方输入的数据的double类型的,所以这里用Double
System.out.println(din.readDouble());
din.close();
}


 

 

 

 

7.对象流

实现接口时,需要打开IDEA的快捷键

进入setting→inspections→serialization issues→选择图中的选项

IO流笔记_字节流

IO流笔记_输出流_02

然后在上图位置就可实现自动生产id

 

注意:对象的序列化与反序列化使用的类要严格一致,包名、类名、类结构所有的都要一致,不然就会异常

 

 

8.随机存储流

RanbdomAccessFile类程序支持"随机访问的方式",程序可以直接跳到任意的地方来读、写

支持只访问文件的部分内容

可以向已存文件后追加内容。

RandomAccessFile对象包含一个记录指针,用来标记当前读到的位置

RandomAccessFile类对象可以自由移动记录指针;

一些方法:long getFilePointer():获取文件记录指针的当前位置

void seek(long pos):将文件记录指针定位到pos位置

实例

public void  xxxxxx(){
//RandomAccessFile的构造有两个参数,参数1是写到文件的路径
//参数二是指定的RandomAccessFile的访问模式
//r:以只读的方式打开
//rw:打开以方便读取和写入
//rwa:打开以方便读取和写入,同步文件内容的更新
//rws:打开以方便读取和写入,同步文件内容的元数据的更新
RandomAccessFile ra = new RandomAccessFile("参数1","参数二(这里用r)");
//pos:读的位置
//ra.seek(0);
//注意转义符的存在也会影响读的位置
ra.seek(10);//void seek(long pos):将文件记录指针定位到pos位置
byte []b=new byte[1024];
int len=0;
while ((len=ra.read(b)) !=-1){
System.out.println(new String(b,0,len));
}
ra.close();
}
2.public void xxxxxx(){
RandomAccessFile rw = new RandomAccessFile("参数1", "rw");
//选择写的位置
//rw.seek(0);
//rw.length是从当前文件的结尾开始输入,也就是追加内容
rw.seek(rw.length());
//获取文件记录指针的当前位置
System.out.println(rw.getFilePointer());
rw.write("good".getBytes());
rw.close();
}