黑马程序员-java io(Input Output)流

时间:2023-02-19 17:28:12

----------- android培训java培训、java学习型技术博客、期待与您交流! ------------

什么是IO呢?

IO就是输入(input)和输出(output),其实在计算机中对数据的操作就是读(输入)和写(输出)的过程。而在java中对数据的操作是通过流的方式,输入和输出是针对数据流的流动方式的一个描述。

输入:将外部中的数据读取到内存中

输出:将内存中数据写入到外部中


IO的作用:是用来处理设备(内存、硬盘)之间的数据传输的


按照不同的形式可以把流进行如下分类:

1.按照流所处理的数据类型:

字节流:用于处理字节数据,可以处理计算机中任一类型的文件。

字符流:用于处理Unicode字符数据,这个是基于字符数据处理,所以只能用于字符数据的操作。

2.按照数据流动方向:

输入流:只能进行字节数据的读取,而不能进行写入操作。

输出流:只能进行字符数据的写入,而不能进行读取操作。

字节流的抽象基类:InputStream, OutputStream

字符流的抽象基类:Reader, Writer

注:由这四个类派生出来的子类名称都是以其父类作为子类名的后缀,前缀其功能。

如:InputStream的子类是FileInputStream。

Reader的子类FileReader。


那么根据上面的内容,我们可以知道,

所有输出类的抽象基类:OutputStream,Writer

所有输入类的抽象基类:InputStream  , Reader

IO流是用于操作数据的,那么数据的最常见体现形式是:文件。

需求一:在硬盘上,创建一个文件并写入一些文字数据。

找到一个专门用于操作文件的Writer子类对象。FileWriter。 后缀名是父类名。 前缀名是该流对象的功能。

import java.io.*;
class FileWriterDemo
{
publicstatic void main(String[] args) throws IOException
{
//创建一个FileWriter对象。该对象一被初始化就必须要明确被操作的文件。
//而且该文件会被创建到指定目录下。如果该目录下已有同名文件,将被覆盖。
//其实该步就是在明确数据要存放的目的地。
FileWriterfw = new FileWriter("demo.txt");

//调用write方法,将字符串写入到流中。
fw.write("abcde");

//刷新流对象中的缓冲中的数据。
//将数据刷到目的地中。
//fw.flush();

//关闭流资源,但是关闭之前会刷新一次内部的缓冲中的数据。

//将数据刷到目的地中。

//和flush区别:flush刷新后,流可以继续使用,close刷新后,会将流关闭。

fw.close();
}

}

注:这里涉及一个问题,就是,假如我们fw.write("abcde");了,没有fw.flush();那么数据还保存在缓冲中,没有写入到文件。只有通过刷新流对象中的缓冲中的数据,才能将数据刷到目的地中。

需求二: 在硬盘上,读取一个文件,并打印在控制台上

找到一个专门用于操作文件的Reader子类对象。FileReader。 后缀名是父类名。 前缀名是该流对象的功能。

import java.io.*;
class FileReaderDemo
{
publicstatic void main(String[] args) throws IOException
{
//创建一个文件读取流对象,和指定名称的文件相关联。
//要保证该文件是已经存在的,如果不存在,会发生异常FileNotFoundException
FileReaderfr = new FileReader("demo.txt");

//调用读取流对象的read方法。
//read():一次读一个字符。而且会自动往下读。


/* 第一种方法:一个一个读取文件中数据*/
intch = 0;
//简写形式
while((ch=fr.read())!=-1)
{
System.out.println("ch="+(char)ch);
}
/*
//这里清晰的解释它的操作过程
while(true)
{
intch = fr.read();
if(ch==-1)
break;
System.out.println("ch="+(char)ch);
}
*/

/*
//第二种方法:通过字符数组进行读取。
//定义一个字符数组。用于存储读到字符。
//该read(char[])返回的是读到字符个数。
char[]buf = new char[1024];
intnum = 0;
while((num=fr.read(buf))!=-1)
{
System.out.println(newString(buf,0,num));
}
*/
fr.close();
}
}

LineNumberReader类:可以提供行号的读取和设置

方法是:setLineNumber(行号);  getLineNumber();

根据上面的需求,我们要是做一个文件复制呢?那么是不是,先读一个A文件的字符内容,然后再写到B文件去,这么一个一个的操作,是不是效率很慢?为此,java提供了流的缓冲区,缓冲区的出现是为了提高流的操作效率而出现的。

缓冲区原理:就是从源中获取一批数据先放在缓冲区(指定的内存区域)中,然后在读取缓冲区的数据,读取完成后,再从源中获取一批数据放进缓冲区,当源中的数据取光时,用-1作为结束标记。

字符流的缓冲区对应的类:BufferedReader     ,BufferedWriter

字节流的缓冲区对应的类:BufferedInputStream,BufferedOutputStream

实例一:BufferedWriter的使用方法

import java.io.*;
class BufferedWriterDemo
{
publicstatic void main(String[] args) throws IOException
{
//创建一个字符写入流对象。
FileWriterfw = new FileWriter("buf.txt");

//为了提高字符写入流效率。加入了缓冲技术。
//只要将需要被提高效率的流对象作为参数传递给缓冲区的构造函数即可。
BufferedWriterbufw = new BufferedWriter(fw);

for(intx=1; x<5; x++)
{
bufw.write("abcd"+x);
bufw.newLine();
bufw.flush(); //这里使用的原因是,读取的数据都会放在缓冲区,也就是内存中,当断电的时候,内存中的数据就没有了,那么数据又没有写入到指定的目的地,会出现安全隐患。
}

//记住,只要用到缓冲区,就要记得刷新。
//bufw.flush();

//其实关闭缓冲区,就是在关闭缓冲区中的流对象。
bufw.close();

}
}

实例二:BufferedReader的使用

import java.io.*;
class BufferedReaderDemo
{
publicstatic void main(String[] args) throws IOException
{
//创建一个读取流对象和文件相关联。
FileReaderfr = new FileReader("buf.txt");

//为了提高效率。加入缓冲技术。将字符读取流对象作为参数传递给缓冲对象的构造函数。
BufferedReaderbufr = new BufferedReader(fr);
Stringline = null;
while((line=bufr.readLine())!=null)
{
System.out.print(line);
}
bufr.close();
}
}

注:

1.对与缓冲区是对于流对象的操作,所以在创建缓冲区之前,必须先有流对象。

2.BufferedReader提供了readLine()方法用于读取一行字符串(以\r或\n分隔),只返回回车符之前的数据内容,不包含并不返回回车符。当返回null时,表示读到文件末尾。

3.BufferedWriter提供了newLine()用于写入一个行分隔符,这里方法具有跨平台性。

4.对于输出的缓冲流,写出的数据会先在内存中缓存,使用flush()方法将会使内存中的数据立刻写出。


流操作的基本规律:

最痛苦的就是流对象有很多,不知道该用哪一个。

通过三个明确来完成。

1,明确源和目的。

       源:输入流。InputStream  Reader

       目的:输出流。OutputStream  Writer。

2,操作的数据是否是纯文本。

       是:字符流。

       不是:字节流。

3,当体系明确后,在明确要使用哪个具体的对象。

       通过设备来进行区分:

       源设备:内存,硬盘。键盘

       目的设备:内存,硬盘,控制台。


转换流:

什么时候使用转换流?

1. 字符和字节之间的转换。

2. 涉及到字符编码转换时。

实例:FileWriter是使用的默认编码表(GBK.),要是操作存储时,需要加入指定编码表utf-8。而指定的编码表只有转换流可以指定。所以要使用的对象是OutputStreamWriter。

那么转换流,在Java中有那些呢?

InputStreamWriter : 字节流通向字符流的桥梁。

OutputStreamWriter:字符转成字节的桥梁。

实例:字节流对象转成字符流对象的过程

//获取键盘录入对象。

     //InputStream in =System.in;

//将字节流对象转成字符流对象,使用转换流。InputStreamReader

     //InputStreamReader isr =new InputStreamReader(in);

     //为了提高效率,将字符串进行缓冲区技术高效操作。使用BufferedReader

     //BufferedReader bufr =new BufferedReader(isr);


File类:是一个专门操作文件的类.

其中需要注意的:

1. File.separator跨平台的分隔符,提高了兼容性。

File类的一些常用的方法,如下:

1:创建:

boolean createNewFile();//创建文件,在指定位置创建文件,如果该文件已经存在,则不创建,返回false

boolean mkdir();//创建文件夹

boolean mkdirs()//创建多级文件夹

2:删除:

boolean delete()  //删除失败返回false。如果文件正在被使用,则删除不了返回false

对于删除目录的时候:必须要由内向外删,目录里有内容删除不掉

void deleteOnExit()   //在退出时删除,也就是说在程序退出时删除指定文件

3:判断:

canExecute()判断文件是否可以执行

boolean exists():文件或目录是否存在**

isFile()判断是否是文件,必须要先判断该文件是否存在?

isDirectory();判断抽象路径名是否是一个目录,

isHidden();判断指定的文件是否是一个隐藏文件

isAbsolute();是否是绝对路径名

4:获取信息

getName();获取文件名

getParent()获取路径

getAbsoluteFile();获取一个绝对路径名,返回file

getAbsolutePath();获取一个绝对路径名,返回String

renameTo(file)  //重命文件,也类似剪切

long lastModified()//获取文件最后一次被修改的时间

long length() 获取文件长数

File[] listRoots():列出可用的盘符

String[] list();列出目录下的所有文件:包含隐藏文件,给定的对象内必须是有效的目录,不然会异常

File[] listFiles();获取目录下所以文件。