Java的核心库java.io提供了全面的IO接口。包括:文件读写、标准设备输出等。Java中IO是以流为基础进行输入输出的,全部数据被串行化写入输出流,或者从输入流读入。java
java.io经过数据流、序列化和文件系统提供系统输入和输出。数组
文件File 位于java.io包中,用于描述文件和目录的操做。
File类这个名字有必定的误导性;咱们可能会认为它指代的是文件,但并不是如此。它既能表明一个特定文件的名称,又能表明一个目录下的一组文件的名称。实际上FilePath(文件路径)对这个类来讲是个更好的名字。
建立文件对象以下:网络
File file = new File("input.txt");//文件位于当前目录下 File file = new File("/home/user","input.txt");//文件位于/home/user目录下
除了上述的File构造方法以外,还有不少和File相关的方法以下:dom
exists() 判断文件或目录是否存在 mkdir() 建立目录 isFile()/isDirectory() 判断是文件仍是目录 delete() 删除文件 getPath() 获取文件或者目录的路径 list() 将目录中全部文件名保存在字符串数组中返回
例 文件相关操做测试
import java.io.*; public class TestAbstract { public static void main(String args[]) throws IOException { File dir = new File("D:/java"); File file1 = new File(dir, "fileTest001.txt"); File file2 = new File(dir, "fileTest002.java"); if (!dir.exists()) dir.mkdir(); if (!file1.exists()) file1.createNewFile(); if (!file2.exists()) file2.createNewFile(); System.out.println("file1's AbsolutePath= " + file1.getAbsolutePath()); System.out.println("file2's AbsolutePath= " + file2.getAbsolutePath()); System.out.println("file1 Canread=" + file1.canRead()); System.out.println("file1's len= " + file1.length()); String[] fileList = dir.list(); System.out.println("there are " + fileList.length + " file(s) in D:"); } } 运行结果: D:\java>java TestAbstract file1's AbsolutePath= D:\java\fileTest001.txt file2's AbsolutePath= D:\java\fileTest002.java file1 Canread=true file1's len= 0 there are 133 file(s) in D:
例 删除目录及文件编码
import java.io.File; public class DeleteFileDemo { public static void main(String args[]) { // 这里修改成本身的测试目录 File folder = new File("/tmp/java/"); deleteFolder(folder); } //删除文件及目录 public static void deleteFolder(File folder) { File[] files = folder.listFiles(); if(files!=null) { for(File f: files) { if(f.isDirectory()) { deleteFolder(f); } else { f.delete(); } } } folder.delete(); } }
流是一个很形象的概念,当程序须要读取数据的时候,就会开启一个通向数据源的流,这个数据源能够是文件,内存,或是网络链接。相似的,当程序须要写入数据的时候,就会开启一个通向目的地的流。这时候你就能够想象数据好像在这其中“流”动同样。
在计算机中,I/O流通常就是指输入输出过程当中传输的的数据序列,是一个抽象的概念,即在输入输出设备之间的传输,一种有顺序的,有起点和终点的字节集合。
设计
按数据传输单位分:
字节流: 以字节为单位传输数据的流
字符流: 以字符为单位传输数据的流
按流向分:
输入流: 程序能够从中读取数据的流。(由InputStream(字节流)和Reader(字符流)做为基类)
输出流: 程序能向其中写入数据的流。(由OutputStream(字节流)和Writer(字符流)做为基类)
按功能分:
节点流: 用于直接操做目标设备的流;节点流从一个特定的数据源读写数据,即节点流是直接操做文件,网络等的流,例如FileInputStream和FileOutputStream,他们直接从文件中读取或往文件中写入字节流。
code
public static void main(String[] args) throws IOException { // 节点流FileOutputStream直接以A.txt做为数据源操做 FileOutputStream fileOutputStream = new FileOutputStream("A.txt"); // 过滤流BufferedOutputStream进一步装饰节点流,提供缓冲写 BufferedOutputStream bufferedOutputStream = new BufferedOutputStream( fileOutputStream); // 过滤流DataOutputStream进一步装饰过滤流,使其提供基本数据类型的写 DataOutputStream out = new DataOutputStream(bufferedOutputStream); out.writeInt(3); out.writeBoolean(true); out.flush(); out.close(); // 此处输入节点流,过滤流正好跟上边输出对应,读者可触类旁通 DataInputStream in = new DataInputStream(new BufferedInputStream( new FileInputStream("A.txt"))); System.out.println(in.readInt()); System.out.println(in.readBoolean()); in.close(); }
JDK所提供的全部流类位于java.io包中,都分别继承自如下四种抽象流类。视频
字节流 | 字符流 | |
---|---|---|
输入流 | InputStream | Reader |
输出流 | OutputStream | Writer |
InputStream:继承自InputStream的流都是用于向程序中输入数据的,且数据单位都是字节(8位)。
OutputStream:继承自OutputStream的流都是程序用于向外输出数据的,且数据单位都是字节(8位)。
Reader:继承自Reader的流都是用于向程序中输入数据的,且数据单位都是字符(16位)。
Writer:继承自Writer的流都是程序用于向外输出数据的,且数据单位都是字符(16位)。对象
提示:在最底层,全部的输入/输出都是字节形式的。基于字符的流只为处理字符提供方便有效的方法。
字节流的最顶层是两个抽象类:InputStream和OutputStream,其余关于处理字节的类都是它们的子类,这些子类对不一样的外设进行处理,例如磁盘文件,网络链接,甚至是内存缓冲区。
类名 含义 BufferedInputStream 缓冲输入流 BufferedOutputStream 缓冲输出流 ByteArrayInputStream 从字节数组读取的输入流 ByteArrayOutputStream 向字节数组写入的输出流 DataInputStream 包含读取Java标准数据类型方法的输入流 DataOutputStream 包含编写Java 标准数据类型方法的输出流 FileInputStream 读取文件的输入流 FileOutputStream 写文件的输出流 FilterInputStream 实现 InputStream FilterOutputStream 实现 OutputStream InputStream 描述流输入的抽象类 OutputStream 描述流输出的抽象类 PipedInputStream 输入管道 PipedOutputStream 输出管道 PrintStream 包含print( ) 和 println( )的输出流 PushbackInputStream 支持向输入流返回一个字节的单字节的“unget”的输入流 RandomAccessFile 支持随机文件输入/输出 SequenceInputStream 两个或两个以上顺序读取的输入流组成的输入流
抽象类InputStream 和 OutputStream中定义了实现其余流类的关键方法read()和write(),它们分别对数据的字节进行读写。两种方法都是抽象方法,被子类重载。
继承自InputStream/OutputStream的流都是用于向程序中输入/输出数据,且数据的单位都是字节(byte=8bit),如图,深色的为节点流,浅色的为过滤流。
例:文件按字节流的方式拷贝
import java.io.*; //文件按字节流的方式拷贝 public class Main { public static void main(String[] args) throws IOException { FileInputStream in = null; FileOutputStream out = null; try{ in = new FileInputStream("input.txt"); out = new FileOutputStream("output.txt"); int c = 0; while((c = in.read())!=-1) { out.write(c); } }finally{ if(in != null) { in.close(); } if(out != null) { out.close(); } } } }
上例中使用的是文件名来建立FileInoutStream和FileOutputStream,实际上能够还可使用文件对象来建立输入输出流。字节流的每次操做都是一个数据单位——字节,假如input.txt文件中包含 Hello world ,那么它将复制完“H”以后,再复制“e”,接着就是“l”,如此类推直到其结束。in.read()每次从输入流中读取一个字节,若是达到文件末尾就返回-1。使用完了,还要关闭这些字节流,调用close()方法。
java是使用16-bits来存储字符数据的,涉及到的大可能是字符操做,在程序中使用字符流会比字节流更加合适。相似于字节流,字符流的两个顶层抽象类是Reader和Writer,一下是它们的子类处理字符流。
类名 含义 BufferedReader 缓冲输入字符流 BufferedWriter 缓冲输出字符流 CharArrayReader 从字符数组读取数据的输入流 CharArrayWriter 向字符数组写数据的输出流 FileReader 读取文件的输入流 FileWriter 写文件的输出流 FilterReader 过滤读 FilterWriter 过滤写 InputStreamReader 把字节转换成字符的输入流 LineNumberReader 计算行数的输入流 OutputStreamWriter 把字符转换成字节的输出流 PipedReader 输入管道 PipedWriter 输出管道 PrintWriter 包含print( )和println( )的输出流 PushbackReader 容许字符返回到输入流的输入流 Reader 描述字符流输入的抽象类 StringReader 读取字符串的输入流 StringWriter 写字符串的输出流 Writer 描述字符流输出的抽象类
相似于字节,字符的抽象类Reader和 Writer中也定义了关键方法read()和write(),它们分别对字符进行读写。两种方法也都是抽象方法,被子类重载。
继承自Reader/Writer的流都是用于向程序中输入/输出数据,且数据的单位都是字符(2byte=16bit),如图,深色的为节点流,浅色的为过滤流。
例:文件按字符流的形式拷贝
import java.io.*; public class CopyFileCharacter { public static void main(String args[]) throws IOException { FileReader in = null; FileWriter out = null; try { in = new FileReader("input.txt"); out = new FileWriter("output.txt"); int c; while ((c = in.read()) != -1) { out.write(c); } }finally { if (in != null) { in.close(); } if (out != null) { out.close(); } } } }
对比发现,只有声明的I/O流的类名不一样,这里使用的FileReader和FileWriter,它们操做的最小单位是一个字符16bits,而FileInputStream和FileOutputStream最小单位则是一个字节8bits.
标准输入流 System.in 读取标准输入设备数据,例如键盘输入(默认),其类型是InputStream,三个重要的读入方法:
int read() 从输入流中读取数据的下一个字节,返回ASCII码。若,返回值=-1,说明没有读取到任何字节读取工做结束 int read(byte[] b) 从输入流中读取必定数量的字节,并将这些数据存储到缓冲区数组b中 int read(byte[] b, int off, int len) 将输入流中最多len个字节读入到字节数组b中
标准输出流 System.out 向标准的输出设备写入数据,默认状况下指控制台,其类型是PrintStream,包含两个重要的方法:print()(不换行)和println()(输出以后换行)
标准错误流 System.err 默认也是控制台,类型和System.out相同是PrintStream,
提示:这些流都有默认的设备,但它们能够重定向到任何兼容的输入/输出设备。
InputStream 和OutputStream,两个是为字节流设计的,主要用来处理字节或二进制对象,
Reader和 Writer.两个是为字符流(一个字符占两个字节)设计的,主要用来处理字符或字符串.
字符流处理的单元为2个字节的Unicode字符,操做字符、字符数组或字符串,
字节流处理单元为1个字节,操做字节和字节数组。
因此字符流是由Java虚拟机将字节转化为2个字节的Unicode字符为单位的字符而成的,
因此它对多国语言支持性比较好!
若是是音频文件、图片、歌曲,就用字节流好点,
若是是关系到中文(文本)的,用字符流好点
全部文件的储存是都是字节(byte)的储存,在磁盘上保留的并非文件的字符而是先把字符编码成字节,再储存这些字节到磁盘。在读取文件(特别是文本文件)时,也是一个字节一个字节地读取以造成字节序列
字节流可用于任何类型的对象,包括二进制对象,而字符流只能处理字符或者字符串;
字节流提供了处理任何类型的IO操做的功能,但它不能直接处理Unicode字符,而字符流就能够
字节流是最基本的,全部的InputStrem和OutputStream的子类都是,主要用在处理二进制数据,它是按字节来处理的
但实际中不少的数据是文本,
又提出了字符流的概念,
它是按虚拟机的encode来处理,也就是要进行字符集的转化
这两个之间经过 InputStreamReader,OutputStreamWriter来关联,
其实是经过byte[]和String来关联
在实际开发中出现的汉字问题实际上都是在字符流和字节流之间转化不统一而形成的
Reader类的read()方法返回类型为int :做为整数读取的字符(占两个字节共16位),范围在 0 到 65535 之间 (0x00-0xffff),若是已到达流的末尾,则返回 -1
inputStream的read()虽然也返回int,但因为此类是面向字节流的,一个字节占8个位,因此返回 0 到 255 范围内的 int 字节值。若是由于已经到达流末尾而没有可用的字节,则返回值 -1。所以对于不能用0-255来表示的值就得用字符流来读取!好比说汉字.
字节流和字符流的主要区别是什么呢?
上面两点能说明什么呢?
针对第一点,
咱们知道,若是一个程序频繁对一个资源进行IO操做,效率会很是低。此时,经过缓冲区,先把须要操做的数据暂时放入内存中,之后直接从内存中读取数据,则能够避免屡次的IO操做,提升效率
针对第二点,
真正存储和传输数据时都是以字节为单位的,字符只是存在与内存当中的,因此,字节流适用范围更为宽广
节点流类型常见的有:
对文件操做的字符流有FileReader/FileWriter,字节流有FileInputStream/FileOutputStream。
过滤流类型常见的有:
缓冲流:缓冲流要“套接”在相应的节点流之上,对读写的数据提供了缓冲的功能,提升了读写效率,同时增长了一些新的方法。
字节缓冲流有BufferedInputStream/BufferedOutputStream;
字符缓冲流有BufferedReader/BufferedWriter,字符缓冲流分别提供了读取和写入一行的方法ReadLine和NewLine方法。
对于输出地缓冲流,写出的数据,会先写入到内存中,再使用flush方法将内存中的数据刷到硬盘。因此,在使用字符缓冲流的时候,必定要先flush,而后再close,避免数据丢失。
转换流:用于字节数据到字符数据之间的转换。
仅有字符流InputStreamReader/OutputStreamWriter。其中,InputStreamReader须要与InputStream“套接”,OutputStreamWriter须要与OutputStream“套接”。
数据流:提供了读写Java中的基本数据类型的功能。
DataInputStream和DataOutputStream分别继承自InputStream和OutputStream,须要“套接”在InputStream和OutputStream类型的节点流之上。
对象流:用于直接将对象写入写出。
流类有ObjectInputStream和ObjectOutputStream,自己这两个方法没什么,可是其要写出的对象有要求,该对象必须实现Serializable接口,来声明其是能够序列化的。不然,不能用对象流读写。
还有一个关键字比较重要,transient,因为修饰实现了Serializable接口的类内的属性,被该修饰符修饰的属性,在以对象流的方式输出的时候,该字段会被忽略。