IO(Input Output)流
IO流用来处理设备之间的数据传输
Java对数据的操作是通过流的方式
Java用于操作流的对象都在IO包中
流按操作数据分为两种:字节流与字符流
流按流向分为:输入流,输出流。
字符流是基于字节流的。字符流的对象里融合了编码表 ,可以指定编码表。这样处理文字的时候会变得很方便。
字节流的抽像基类:
InputStream,OutputStream.
字符流的抽象基类:
Reader,Writer.
注意:由这四个基类派生出来的子类名称都是以其父类名作为子类名的后缀。
如:InputStream的子类FilelnputStream.
如:Reader的子类FileReader.
操作文件的Writer子类对象 FileWriter。 后缀名是父类名。 前缀名是该流对象的功能。
创建一个FileWriter对象。该对象一被初始化就必须要明确被操作的文件。
而且该文件会被创建到指定目录下。如果该目录下已有同名文件,将被覆盖。
其实该步就是在明确数据要存放的目的地
FileWriter fw = new FileWriter("demo.txt");
调用write方法,将字符串写入到流中。
创建一个FileWriter对象。该对象一被初始化就必须要明确被操作的文件。
而且该文件会被创建到指定目录下。如果该目录下已有同名文件,将被覆盖。
其实该步就是在明确数据要存放的目的地。
FileWriter fw = new FileWriter("demo.txt");
调用write方法,将字符串写入到流中。
fw.write("abcde");
刷新流对象中的缓冲中的数据。
将数据刷到目的地中。
fw.flush();
关闭流资源,但是关闭之前会刷新一次内部的缓冲中的数据。
将数据刷到目的地中。
和flush区别:flush刷新后,流可以继续使用,close刷新后,会将流关闭。
fw.close();
拷贝文本文件
将C盘一个文本文件复制到D盘。
复制的原理:
其实就是将C盘下的文件数据存储到D盘的一个文件中。
步骤:
1,在D盘创建一个文件。用于存储C盘文件中的数据。
2,定义读取流和C盘文件关联。
3,通过不断的读写完成数据存储。
4,关闭资源。
字符流的缓冲区
缓冲区的出现提高了对数据的读写效率。
对应类
BufferedWriter
BufferedReader
BufferedWriter:
缓冲区要结合流才可以使用。
在流的基础上对流的功能进行了增加。
缓冲区的出现是为了提高流的操作效率而出现的。
所以在创建缓冲区之前,必须要先有流对象。
FileWriter fw =new FileWriter("buf.txt");
创建一个字符写入流对象。
BufferedWriter bufw =new BufferedWriter(fw);
bufw.write("avc");
记住,只要用到了缓冲区,就要记得刷新。
bufw.flush();
其实关闭 缓冲区,就是爱关闭缓冲区中的流对象。
bufw.close();
所以fw.close();就不用写了。
该缓冲区中提供了一个跨平台的换行符。
newLine();
BufferedReader:
字符读取流缓冲区:
该缓冲区提供了一个一次读一行的方法readLine,方便于对文本数据的获取。
当返回null时,表示读到文件末尾。
FileReader fr = new FileReader("buff.txt");
创建一个读取流对象和文件相关联。
BufferedReader bufr = new BufferedReader(fr);
为了提高效率,加入了缓冲技术。将字符读取流对象作为参数传递给缓冲对象的构造函数。
String line = null;
while((line=bufr.readLine())!=null)
{
System.out.println(line);
}
bufr.close();
readLine方法的原理
无论是读一行,或者是读取多个字符。其实最终都是在硬盘上一个一个读取。所以最终使用的还是read方法一次读一个的方法
装饰设计模式:
当想要对已有的对象进行功能增加时,
可以定义类,将已有对象传入,基于已有的功能,并提供加强功能。
那么自定义的该类称为装饰类。
装饰和继承的区别
装饰模式比继承要灵活,避免了继承体系的臃肿。
而且降低了类与类之间的关系。
装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强的功能。
所以装饰类和被装饰类通常都是属于一个体系中的。
LineNumberReader
里面有2个功能:
setLineNumber();设置起始行号
getLineNumber();获取行号
字符流:
FileReader
FileWriter
BufferedReader
BufferedWriter
字节流:
InputStream 读 OutputStream 写,凡是输出的都是写。
读取键盘录入。
System.out:对应的是标准输出设备,控制台。
System.in:对应的是标准输入设备,键盘。
InputStreamReader 字节流转换成字符流的桥梁。
OutputStreamWriter 字符流通向字节流的桥梁。
流操作的基本规律:
这需要通过三个明确来完成。
1,明确源和目的。
源:输入流。InputStream Reader
目的:输出流。OutputStream Writer。
2,操作的数据是否是纯文本。
是:字符流。
不是:字节流。
3,当体系明确后,在明确要使用哪个具体的对象。
通过设备来进行区分:
源设备:
内存--ArrayStream
硬盘--FileStream
键盘--System.in
目的设备:
内存--ArrayStream
硬盘--FileStream
控制台--System.out
将一个文本文件中数据存储到另一个文件中。复制文件。
源:因为是源,所以使用读取流。InputStream Reader
是不是操作文本文件。
是!这时就可以选择Reader
这样体系就明确了。
接下来明确要使用该体系中的哪个对象。
明确设备:硬盘。上一个文件。
Reader体系中可以操作文件的对象是 FileReader
是否需要提高效率:是!。加入Reader体系中缓冲区 BufferedReader.
FileReader fr = new FileReader("a.txt");
BufferedReader bufr = new BufferedReader(fr);
目的:OutputStream Writer
是否是纯文本。
是!Writer。
设备:硬盘,一个文件。
Writer体系中可以操作文件的对象FileWriter。
是否需要提高效率:是!。加入Writer体系中缓冲区 BufferedWriter
FileWriter fw = new FileWriter("b.txt");
BufferedWriter bufw = new BufferedWriter(fw);
需求:将键盘录入的数据保存到一个文件中。
这个需求中有源和目的都存在。
那么分别分析
源:InputStream Reader
是不是纯文本?是!Reader
设备:键盘。对应的对象是System.in.
不是选择Reader吗?System.in对应的不是字节流吗?
为了操作键盘的文本数据方便。转成字符流按照字符串操作是最方便的。
所以既然明确了Reader,那么就将System.in转换成Reader。
用了Reader体系中转换流,InputStreamReader
InputStreamReader isr = new InputStreamReader(System.in);
需要提高效率吗?需要!BufferedReader
BufferedReader bufr = new BufferedReader(isr);
目的:OutputStream Writer
是否是存文本?是!Writer。
设备:硬盘。一个文件。使用 FileWriter。
FileWriter fw = new FileWriter("c.txt");
需要提高效率吗?需要。
BufferedWriter bufw = new BufferedWriter(fw);
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
File类
用来将文件或者文件夹封装成对象
方便对文件与文件夹的属性信息进行操作。
File对象可以作为参数传递给流的构造函数。
了解File类中的常用方法。
File f =new File("a.txt");
将a.txt封装成file对象。可以将已有的和未出现的文件或者文件夹封装成对象。
File类常见的方法:
1.创建
boolean createNewFile():创建一个新的空文件,不过该文件已存在,就不会创建,返回false.
和输出流不一样,输出流对象一建立创建文件。而且文件已经存在,会覆盖。
boolean mkdir():创建文件夹。
boolean mkdirs():创建多级文件夹。
2.删除
boolean delete():删除文件或目录,删除失败返回false.
void deleteOnExit():虚拟机结束时,会自动删除指定的文件和目录。
3.判断
boolean exists():判断此路径名表示的文件或目录是否存在
boolean isFile():判断此路径名表示的文件或目录是否是一个标准的文件
boolean isDirectory():判断此路径名表示的文件或目录是否是一个目录
在判断文件对象是否是文件或者目录时,必须要先判断该文件对象封装的内容是否存在。通过exists判断。
isHidden(),是否是隐藏的。
isAbsolute(),是否是绝对路径。
4.获取
String getAbsolutePath():绝对路径
String getPath():相对路径
String getParent():返回此路径名父目录的路径,如果没有则返回null
String getName():返回此路径名表示的文件或目录的名称
long length():返回此路径名表示的文件的长度
long lastModified():返回此文件最后一次被修改的时间
递归
什么是递归?
递归就是函数自身调用自身。
递归需要注意
1,限定条件
2,要注意递归的次数,尽量避免内存溢出。
Properties是hashtable的子类。
也就是说它具备map集合的特点,而且它里面存储的键值对都是字符串
是集合中和IO技术相结合的集合容器。
该对象的特点:可以用于键值对形式的配置文件。
在加载数据时,需要数据有固定格式:键=值。
打印流
PrintWriter与PrintStream
可以直接操作输入流和文件。
序列流
SequencelnputStream
对多个流进行合并。
操作对象
ObjectInputStream与ObjectOutputStream
被操作的对象需要实现Serializable(标记接口);
打印流
该流提供了打印方法,可以将各种数据类型的数据都原样打印。
字节打印流:
PrintStream
构造函数可以接收的参数类型:
1,file对象。File
2,字符串路径。String
3,字节输出流。OutputStream
字符打印流:
PrintWriter
构造函数可以接收的参数类型:
1,file对象。File
2,字符串路径。String
3,字节输出流。OutputStream
4,字符输出流,Writer。
RandomAccessFile
随机访问文件,自身具备读写的方法。
通过skipBytes(int x),seek(int x)来达到随机访问。
内部封装了一个数组,而且通过指针对数组的元素进行操作。
可以通过getFilePointer获取指针位置,同时可以通过seek改变指针位置。
该类只能操作文件。
而且操作文件还有模式:只读r,,读写rw等。
如果模式为只读r,,不会创建文件。会去读取一个已存在文件,如果该文件不存在,则会出现异常。
如果模式为rw操作的文件不存在,会自动创建。如果存在则不会覆盖。
RandomAccessFile raf = new RandomAccessFile("","r");
seek(int x)
skipBytes(int x)
IO包中的其他类
操作基本数据类型
DataInputStream与DataOutputStream--可以用于操作基本数据类型的数据的流对象。
操作字节数组
ByteArrayInputStream--在构造的时候,需要接收数据源,而且数据源是一个字节数组。
ByteArrayOutputStream--在构造的时候,不用定义数据目的,因为该对象中已经内部封装了可变长度的字节数组。这就是数据目的地。
这两个流对象都操作的数组,并没有使用系统资源,不用进行close关闭。
操作字符数组
CharArrayReader与CharArrayWrite
操作字符串
StringReader与StringWriter
字符编码
字符流的出现为了方便操作字符。
更重要的是加入了编码转换。
通过子类转换流来完成。
------------InputStreamReader
------------OutputStreamWriter
在两个对象进行构造的时候可以加入字符集。
编码:字符串变成字节数组。
解码:字节数组变成字符串。
String-->byte[]; str.getBytes(charsetName);
byte[] -->String: new String(byte[],charsetName);
*/
import java.util.*;
class EncodeDemo
{
public static void main(String[] args)throws Exception
{
String s = "哈哈";
byte[] b1 = s.getBytes("GBK");
System.out.println(Arrays.toString(b1));
String s1 = new String(b1,"utf-8");
System.out.println("s1="+s1);
//对s1进行iso8859-1编码。
byte[] b2 = s1.getBytes("utf-8");
System.out.println(Arrays.toString(b2));
String s2 = new String(b2,"gbk");
System.out.println("s2="+s2);
}
}
管道流
PipedInputStream和PipedOutputStream
输入输出可以直接进行连接,通过结合线程使用。
需要和多线程技术相结合的流对象。
特点:
1,可以将管道输出流连接到管道输入流通信管道。
2,需要和多线程技术相结合的流对象。
常见的码表有哪些,都有什么特点?
ASCll:美国标准信息交换码
用一个字节的7位可以表示
ISO8859-1:拉丁码表。欧洲码表
用一个字节的8位表示
GB2312:中国的中文编码表
GBK:中国的中文编码表升级,融合了更多的中文文字字符号。
Unicode:国际标准码,融合了多种文字。
所有文字都用两个字节来表示,Java语言使用的就是unicode
UTF-8:最多用三个字节来表示一个字符