JavaIO--01

1.简介

java.io 包几乎包含了所有操作输入、输出需要的类。所有这些流类代表了输入源和输出目标。java.io 包中的流支持很多种格式,比如:基本类型、对象、本地化字符集等等。一个流可以理解为一个数据的序列。输入流表示从一个源读取数据,输出流表示向一个目标写数据。Java 为 I/O 提供了强大的而灵活的支持,使其更广泛地应用到文件传输和网络编程中。

Java 的 I/O 大概可以分成以下几类:
  磁盘操作:File
  字节操作:InputStream 和 OutputStream
  字符操作:Reader 和 Writer
  对象操作:Serializable
  网络操作:Socket
  新的输入/输出:NIO

2.File
Java中IO操作有相应步骤,以文件操作为例,主要操作流程如下:
1.使用File类打开一个文件
2.通过字节流或字符流的子类,指定输出的位置
3.进行读/写操作
4.关闭输入/输出

那么我们先来介绍一下File类
Java文件类在java.io包中,它以抽象的方式代表文件名和目录路径名。该类主要用于获取文件和目录的属性,文件和目录的创建、查找、删除、重命名等,但不能进行文件的读写操作。
File对象代表磁盘中实际存在的文件和目录。通过以下构造方法创建一个File对象。

通过给定的父抽象路径名和子路径名字符串创建一个新的File实例:File(File parent, String child)

通过将给定路径名字符串转换成抽象路径名来创建一个新 File 实例:File(String pathname)

根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例:File(String parent, String child)

通过将给定的 file: URI 转换成一个抽象路径名来创建一个新的 File 实例:File(URI uri)

注意:
1.在各个操作系统中,路径的分隔符是不一样的,例如:Windows中使用反斜杠:"\",Linux|Unix中使用正斜杠:"/"。在使用反斜杠时要写成"\\"的形式,因为反斜杠要进行转义。如果要让Java保持可移植性,应该使用File类的静态常量File.pathSeparator。
2.构建一个File实例并不会在机器上创建一个文件。不管文件是否存在,都可以创建任意文件名的File实例。可以调用File实例上的exists()方法来判断这个文件是否存在。通过后续的学习我们会知道,当把一个输出流绑定到一个不存在的File实例上时,会自动在机器上创建该文件,如果文件已经存在,把输出流绑定到该文件上则会覆盖该文件,但这些都不是在创建File实例时进行的

创建File对象成功后,可以使用以下列表中的方法操作文件。

public String getName();//获取文件或目录名称
public String getParent();//获取文件或目录的父路径字符串,如果没有指定父目录,返回null
public File getParentFile();//获取文件或目录的父目录对象,如果没有,返回null
public String getPath();//获取路径字符串
public boolean isAbsolute();//判断路径是否是绝对路径
public boolean canRead();//判断是否可读
public boolean canWrite();//判断是否可写
public boolean exists();//判断文件是否存在
public boolean isDirectory();//判断此抽象路径表示的文件是否是一个目录
public boolean isFile();//判断是否是文件
public long lastModified();//获取最后一次修改时间戳
public long length();//获取文件长度
public boolean createNewFile() throws IOException;//当且仅当不存在此路径表示的文件时,原子低创建由此路径名表示的空文件
public boolean delete();//删除文件或目录,被删除的目录不能非空,如果非空,需要先递归删除子目录
public String[] list();//返回目录的子文件子目录
public String[] list(FilenameFilter filter);//返回目录的特定格式过滤的子文件子目录
public File[] list();//返回目录的子文件子目录
public File[] list(FilenameFilter filter);//返回目录的特定格式过滤的子文件子目录
public boolean mkdir();//创建目录
public boolean mkdirs();//创建多级目录
public boolean renameTo(File dest);//重命名

 

3.RandomAccessFile
RandomAccessFile不同于File,它提供了对文件内容的访问,可以读写文件且支持随机访问文件的任意位置。RandomAccessFile读写用到文件指针,它的初始位置为0,可以用getFilePointer()方法获取文件指针的位置。
下面是RandomAccessFile常用的方法。
public RandomAccessFile(File file,String mode) throws FileNotFoundException;//构造方法,第二参数为设置模式:“r”只读,“w”只写,“rw”读写
public RandomAccessFile(String fileName,String mode) throws FileNotFoundException;//构造方法,第二参数为设置模式:“r”只读,“w”只写,“rw”读写
public void close() throws IOException ;关闭操作
public int read(byte[] b)throws IOException;//将内容读取到一个byte数组中
public final byte readByte() throws IOException;//读取一个字节
public void seek(long pos) throws IOException;//设置指针读取的位置
public final void writeBytes(String s) throws IOException;//写字符串到文件中
public String readLine();//读取一行

 

 4.流

在Java程序中所有的数据都是以流的方式进行传输或保存的,程序需要数据的时候要使用输入流读取数据,而当程序需要将一些数据保存起来的时候,就要使用输出流完成。程序中的输入输出都是以流的形式保存的,流中保存的实际上全都是字节文件。流涉及的领域很广:标准输入输出,文件的操作,网络上的数据流,字符串流,对象流,zip文件流等等

流具有方向性,至于是输入流还是输出流则是一个相对的概念,一般以程序为参考,如果数据的流向是程序至设备,我们成为输出流,反之我们称为输入流

Java 流的层次图:

4.1.IO流分类
1)按操作数据类型分:字符流和字节流
编码与解码:编码就是把字符转换为字节,而解码是把字节重新组合成字符。如果编码和解码过程使用不同的编码方式那么就出现了乱码。

字符流:Java中的字符流处理的最基本的单元是2字节的Unicode码元(char),它通常用来处理文本数据,如字符、字符数组或字符串等。所谓Unicode码元,也就是一个Unicode代码单元,范围是0x0000~0xFFFF。在以上范围内的每个数字都与一个字符相对应,Java中的String类型默认就把字符以Unicode规则编码而后存储在内存中。然而与存储在内存中不同,存储在磁盘上的数据通常有着各种各样的编码方式。使用不同的编码方式,相同的字符会有不同的二进制表示。实际上字符流是这样工作的:

输出字符流:把要写入文件的字符序列(实际上是Unicode码元序列)转为指定编码方式下的字节序列,然后再写入到文件中。
输入字符流:把要读取的字节序列按指定编码方式解码为相应字符序列(实际上是Unicode码元序列从)从而可以存在内存中。
也就是说,所有的文件在硬盘或在传输时都是以字节的方式进行的,包括图片等都是按字节的方式存储的,而字符是只有在内存中才会形成。

字节流:Java中的字节流处理的最基本单位为单个字节(byte),它通常用来处理二进制数据,如果要得到字节对应的字符需要强制类型转换。

两者比较:
1.字符流是由Java虚拟机将字节转化为2个字节的Unicode字符为单位的字符而成的,所以它对多国语言支持性较好,如果要操作中文数据等,用字符流。
2.字符流只用来处理文本数据,字节流还可以用来处理媒体数据,如视频、音频、图片等。
3.字符流的两个抽象基类为Reader和Writer,字节流的两个抽象基类为InputStream和OutputStream。它们的具体子类名以基类名为后缀进行扩展。
4.字节流在操作的时候不会用到缓冲区(内存),是直接对文件本身操作的,而字符流在操作的时候使用缓冲区

 

 

如果想让缓冲区中的内容输出,要么关闭流强制刷新缓冲区,要么调用flush方法冲刷缓冲区。可以简单地把缓冲区理解为一段特殊的内存。某些情况下,如果一个程序频繁地操作一个资源(如文件或数据库),则性能会很低,此时为了提升性能,就可以将一部分数据暂时读入到内存的一块区域之中,以后直接从此区域中读取数据即可,因为读取内存速度会比较快,这样可以提升程序的性能。
在字符流的操作中,所有的字符都是在内存中形成的,在输出前会将所有的内容暂时保存在内存之中,所以使用了缓冲区暂存数据。

建议:
1.虽然不关闭字节流不影响数据的输出,且后续JVM会自动回收这部分内存,但还是建议在使用完任何流对象之后关闭流。
2.使用流对象都要声明或抛出IOException
3.在创建一个文件时,如果目录下有同名文件将被覆盖
4.在写文件时,如果文件不存在,会在创建输出流对象并绑定文件时自动创建文件,不必使用File的exists方法提前检测
4.在读取文件时,必须使用File的exists方法提前检测来保证该文件已存在,否则抛出FileNotFoundException

2)按流向分:输入流和输出流
输入流:程序从输入流读取数据源。数据源包括外界(键盘、文件、网络等),即是将数据源读入到程序的通信通道。输入流主要包括两个抽象基类:InputStream(字节输入流)和Reader(字符输入流)及其扩展的具体子类。
输出流:程序向输出流写入数据。将程序中的数据输出到外界(显示器、打印机、文件、网络等)的通信通道。输出流主要包括两个抽象基类:OutputStream(字节输出流)和Writer(字符输出流)及其扩展的具体子类。

3)按功能分:节点流和处理流
按照流是否直接与特定的地方(如磁盘、内存、设备等)相连,分为节点流和处理流两类。
节点流:程序用于直接操作目标设备所对应的类叫节点流。(低级流)
处理流:程序通过一个间接流类去调用节点流类,以达到更加灵活方便地读写各种类型的数据,这个间接流类就是处理流。处理流可以看成是对已存在的流进行连接和封装的流。(高级流)

注意:在使用到处理流对流进行连接和封装时,读写完毕只需关闭处理流,不用关闭节点流。处理流关闭的时候,会调用其处理的节点流的关闭方法。如果将节点流关闭以后再关闭处理流,会抛出IO异常

节点流:

File 文件流。对文件进行读、写操作:FileReader、FileWriter、FileInputStream、FileOutputStream。
Memory 流。
向内存数组读写数据: CharArrayReader与 CharArrayWriter、ByteArrayInputStream与ByteArrayOutputStream。
向内存字符串读写数据:StringReader、StringWriter、StringBufferInputStream。
Pipe管道流:实现管道的输入和输出(进程间通信): PipedReader与PipedWriter、PipedInputStream与PipedOutputStream

 

 处理流:

Buffering缓冲流:在读入或写出时,对数据进行缓存,以减少I/O的次数:BufferedReader与BufferedWriter、BufferedInputStream与BufferedOutputStream。
Filtering 滤流:在数据进行读或写时进行过滤:FilterReader与FilterWriter、FilterInputStream与FilterOutputStream。
Converting between Bytes and Characters 转换流:按照一定的编码/解码标准将字节流转换为字符流,或进行反向转换(Stream到Reader):InputStreamReader、OutputStreamWriter。
Object Serialization 对象流 :ObjectInputStream、ObjectOutputStream。
DataConversion数据流:按基本数据类型读、写(处理的数据是Java的基本类型):DataInputStream、DataOutputStream 。
Counting计数流:在读入数据时对行记数 :LineNumberReader、LineNumberInputStream。
Peeking Ahead预读流: 通过缓存机制,进行预读 :PushbackReader、PushbackInputStream。
Printing打印流: 包含方便的打印方法 :PrintWriter、PrintStream。

 

posted @ 2020-12-31 08:51  守望一心  阅读(96)  评论(0编辑  收藏  举报