Java的流(Stream)、文件(File)和IO

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

在 Java 中,一个流被定义为一个数据序列。输入流用于从源读取数据,输出流用于向目标写数据。下图是一个描述输入流和输出流的类层次图:

Java 将流按照读写单位划分为字节流和字符流

  • 字节流:字节流是按照字节的方式读取数据,一次读取一个字节,也就是8个二进制位,这种流是万能的,什么类型的文件都可以读取,包括:文本文件,图片,声音文件,视频文件等。
  • 字符流:读写单位是以字符为单位,所以字符流读取数据有一定的局限性,只能用于读写文本数据。非文本数据不能使用字符流读取(如图片,基本类型数据,Mp3等数据)。

Java 将流按照角色的不同划分为节点流和处理流

  • 节点流:又称为“低级流”,是实际连接程序与另一端的“管道”,负责实际搬运数据,读写一定是建立在低级流的基础上进行的。
  • 处理流:又称为“高级流”,不能独立存在(无意义),高级流一定会连接在其它流上,使得数据”流经“该流时对其进行加工处理,简化我们对数据读写时的某些操作。

读取控制台输入

Java 的控制台输入由 System.in 完成。为了获得一个绑定到控制台的字符流,你可以把 System.in 包装在一个 BufferedReader 对象中来创建一个字符流。下面是创建 BufferedReader 的基本语法:

BufferedReader br = new BufferedReader(new 
                      InputStreamReader(System.in));
复制代码

BufferedReader 缓冲字符输入流,内部拥有缓冲区,可以块读取字符,并且可以按行读取字符,需要使用 InputStreamReader 进行流转换。BufferedReader 对象创建后,我们便可以使用 read() 方法从控制台读取一个字符,或者用 readLine() 方法读取一个字符串。

从控制台读取多字符输入:从 BufferedReader 对象读取一个字符要使用 read() 方法,每次调用 read() 方法,它从输入流读取一个字符并把该字符作为整数值返回。 当流结束的时候返回 -1。该方法抛出 IOException。它的语法如下:

int read( ) throws IOException
复制代码

使用 BufferedReader 在控制台读取字符的实例:

import java.io.*;
 
public class BRRead {
    public static void main(String[] args) throws IOException {
        char c;
        // 使用 System.in 创建 BufferedReader
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        System.out.println("输入字符, 按下 'q' 键退出。");
        // 读取字符
        do {
            c = (char) br.read();
            System.out.println(c);
        } while (c != 'q');
    }
}
// 实例编译运行结果如下:
// 输入字符, 按下 'q' 键退出。
// green
// g
// r
// e
// e
// n


// q
// q

// Process finished with exit code 0
复制代码

从控制台读取字符串:标准输入读取一个字符串需要使用 BufferedReader 的 readLine() 方法,该方法会连续读取若干字符,当读取到换行符时,将之前读取的字符以字符串形式返回(若读取不到换行符,可能会阻塞),若返回值为 null 时,表示流的末尾。它的一般格式是:

String readLine( ) throws IOException
复制代码

使用 BufferedReader 在控制台读取字符的实例:

// 程序读取和显示字符行直到你输入了单词"end"
import java.io.*;
 
public class BRReadLines {
    public static void main(String[] args) throws IOException {
        // 使用 System.in 创建 BufferedReader
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String str;
        System.out.println("Enter lines of text.");
        System.out.println("Enter 'end' to quit.");
        do {
            str = br.readLine();
            System.out.println(str);
        } while (!str.equals("end"));
    }
}
// 实例编译运行结果如下:
// Enter lines of text.
// Enter 'end' to quit.
// 我是菜鸟
// 我是菜鸟
// end
// end

// Process finished with exit code 0
复制代码

控制台输出

在此前已经介绍过,控制台的输出由 print( ) 和 println() 完成。这些方法都由类 PrintStream 定义,System.out 是该类对象的一个引用。PrintStream 继承了 OutputStream类,并且实现了方法 write()。这样,write() 也可以用来往控制台写操作。PrintStream 定义 write() 的最简单格式如下所示:

// 该方法将 byteval 的低八位字节写到流中。
void write(int byteval)
复制代码

System.out.write()实例:

import java.io.*;
 
//演示 System.out.write().
public class WriteDemo {
    public static void main(String[] args) {
        int b;
        b = 'A';
        System.out.write(b);
        System.out.write('\n');
    }
}
// 运行以上实例在输出窗口输出 "A" 字符
// A
复制代码

注意:write() 方法不经常使用,因为 print() 和 println() 方法用起来更为方便。

读写文件

FileInputStream & FileOutputStream 文件流是一对节点流(低级流),用于读写文件数据。功能与RAF一样,但是底层的读写方式不同。流是顺序读写的,而RAF是基于指针随机读写的。

FileInputStream该流用于从文件读取数据,它的对象可以用关键字 new 来创建。有多种构造方法可用来创建对象。

例如可以使用字符串类型的文件名来创建一个输入流对象来读取文件:

InputStream f = new FileInputStream("C:/java/hello");
复制代码

也可以使用一个文件对象来创建一个输入流对象来读取文件。我们首先得使用 File() 方法来创建一个文件对象:

File f = new File("C:/java/hello");
InputStream in = new FileInputStream(f);
复制代码

创建了InputStream对象,就可以使用下面的方法来读取流或者进行其他的流操作:

序号方法及说明
1public void close() throws IOException{},关闭此文件输入流并释放与此流有关的所有系统资源。抛出IOException异常
2protected void finalize()throws IOException {},这个方法清除与该文件的连接。确保在不再引用文件输入流时调用其 close 方法。抛出IOException异常
3public int read(int r)throws IOException{},这个方法从 InputStream 对象读取指定字节的数据。返回为整数值。返回下一字节数据,如果已经到结尾则返回-1
4public int read(byte[] r) throws IOException{},这个方法从输入流读取r.length长度的字节。返回读取的字节数。如果是文件结尾则返回-1
5public int available() throws IOException{},返回下一次对此输入流调用的方法可以不受阻塞地从此输入流读取的字节数。返回一个整数值

FileOutputStream该类用来创建一个文件并向文件中写数据。如果该流在打开文件进行输出前,目标文件不存在,那么该流会创建该文件。有两个构造方法可以用来创建 FileOutputStream 对象。

使用字符串类型的文件名来创建一个输出流对象:

OutputStream f = new FileOutputStream("C:/java/hello")
复制代码

也可以使用一个文件对象来创建一个输出流来写文件。我们首先得使用File()方法来创建一个文件对象:

File f = new File("C:/java/hello");
OutputStream fOut = new FileOutputStream(f);
复制代码

创建OutputStream 对象完成后,就可以使用下面的方法来写入流或者进行其他的流操作:

序号方法及说明
1public void close() throws IOException{},关闭此文件输入流并释放与此流有关的所有系统资源。抛出IOException异常
2protected void finalize()throws IOException {},这个方法清除与该文件的连接。确保在不再引用文件输入流时调用其 close 方法。抛出IOException异常
3public void write(int w)throws IOException{},这个方法把指定的字节写到输出流中
4public void write(byte[] w),把指定数组中w.length长度的字节写到OutputStream中

演示 InputStream 和 OutputStream 用法的实例:

public class fileStreamTest {
    public static void main(String[] args) {
        try {
            //ASCII码
            byte bWrite[] = { 65, 66, 67, 68, 69 };
            //创建输出流
            OutputStream os = new FileOutputStream("test.txt");
            //写出数据
            for (int x = 0; x < bWrite.length; x++) {
                os.write(bWrite[x]); // writes the bytes
            }
            //关闭输出流
            os.close();
 
            //创建输入流
            InputStream is = new FileInputStream("test.txt");
            //可读取字节数的估计值
            int size = is.available();
            //读取数据
            for (int i = 0; i < size; i++) {
                System.out.print((char) is.read() + "  ");
            }
            //关闭输入流
            is.close();
        } catch (IOException e) {
            System.out.print("Exception");
        }
    }
}
// 实例编译运行结果如下:
// A  B  C  D  E  
复制代码

写出文件如下:

上面的程序首先创建文件test.txt,并把给定的数字以二进制形式写进该文件,同时输出到控制台上。

以上代码由于是二进制写入,可能存在乱码,可以使用以下代码实例来解决乱码问题:

//文件名 :fileStreamTest2.java
import java.io.*;
 
public class fileStreamTest2 {
    public static void main(String[] args) throws IOException {
 
        // 构建FileOutputStream对象,文件不存在会自动新建
        File f = new File("a.txt");
        FileOutputStream fop = new FileOutputStream(f);

        // 构建OutputStreamWriter对象,参数可以指定编码,默认为操作系统默认编码,windows上是gbk
        OutputStreamWriter writer = new OutputStreamWriter(fop, "UTF-8");

        // 写入到缓冲区
        writer.append("中文输入");

        // 换行
        writer.append("\r\n");

        // 写入到缓冲区
        writer.append("English");

        // 关闭写入流,同时会把缓冲区内容写入文件
        writer.close();

        // 关闭输出流,释放系统资源
        fop.close();

        // 构建FileInputStream对象
        FileInputStream fip = new FileInputStream(f);

        // 构建InputStreamReader对象,编码与写入相同
        InputStreamReader reader = new InputStreamReader(fip, "UTF-8");


        StringBuffer sb = new StringBuffer();
        while (reader.ready()) {
            // 转成char加到StringBuffer对象中
            sb.append((char) reader.read());
        }
        System.out.println(sb.toString());

        // 关闭读取流
        reader.close();

        // 关闭输入流,释放系统资源
        fip.close();    
    }
}
// 实例编译运行结果如下:
// 中文输入
// English
复制代码

写出文件如下:

一些字符编码简介如下

  • GBK:国标编码,中文占2字节。
  • UTF-8:万国码,对 unicode 进行编码,变长编码集。英文占1字节,中文占3字节。
  • ISO8859-1:欧洲编码集,不支持中文。

FileReader & FileWriter

FileReader 类:从InputStreamReader类继承而来。该类按字符读取流中数据。可以通过以下几种构造方法创建需要的对象:

// 在给定从中读取数据的 File 的情况下创建一个新 FileReader
FileReader(File file)
// 在给定从中读取数据的 FileDescriptor 的情况下创建一个新 FileReader
FileReader(FileDescriptor fd) 
// 在给定从中读取数据的文件名的情况下创建一个新 FileReader
FileReader(String fileName) 
复制代码

创建FIleReader对象成功后,可以参照以下列表里的方法操作文件:

序号方法及说明
1public int read() throws IOException,读取单个字符,返回一个int型变量代表读取到的字符
2public int read(char [] c, int offset, int len),读取字符到c数组,返回读取到字符的个数

FileWriter 类:从 OutputStreamWriter 类继承而来。该类按字符向流中写入数据。可以通过以下几种构造方法创建需要的对象:

// 在给出 File 对象的情况下构造一个 FileWriter 对象
FileWriter(File file)
// 在给出 File 对象的情况下构造一个 FileWriter 对象,并决定是否追加写入
// append 参数为 true,则将字节写入文件末尾处,相当于追加信息。如果 append 参数为 false, 则写入文件开始处
FileWriter(File file, boolean append)
// 构造与某个文件描述符相关联的 FileWriter 对象
FileWriter(FileDescriptor fd)
// 在给出文件名的情况下构造 FileWriter 对象,它具有指示是否追加写入数据的 boolean 值
FileWriter(String fileName, boolean append)
复制代码

创建FileWriter对象成功后,可以参照以下列表里的方法操作文件:

序号方法及说明
1public void write(int c) throws IOException,写入单个字符c
2public void write(char [] c, int offset, int len),写入字符数组中开始为offset、长度为len的某一部分
3public void write(String s, int offset, int len),写入字符串中开始为offset、长度为len的某一部分

使用 FileReader & FileWriter 进行读写的实例:

public class Test {
    public static void main(String args[]) throws IOException {
        // 创建文件
        File file = new File("Hello.txt");
        file.createNewFile();
        // 创建 FileWriter 对象
        FileWriter writer = new FileWriter(file);
        // 向文件写入内容
        writer.write("This\n is\n an\n example\n");
        // 刷新流
        writer.flush();
        // 关闭流
        writer.close();

        // 创建 FileReader 对象
        FileReader fr = new FileReader(file);
        char[] a = new char[50];
        // 读取内容到数组中
        fr.read(a);
        for (char c : a) {
            // 一个一个打印字符
            System.out.print(c);
        }
        // 关闭流
        fr.close();
    }
}

// 以上实例编译运行结果如下:
// This
//  is
//  an
//  example

复制代码

写出文件如下:

InputStreamReader & OutputStreamWriter

它们是一对处理流(高级流),同时也是常用的字符流实现类。在读取文本数据时,使用处理流进行流连接是非常重要的一环,起到承上启下的作用。因为几乎所有的字符流都只能连接在其它流上,而基本上节点流(低级流)都是字节流,由于 InputStreamReader & OutputStreamWriter 可以连接字节流,而其本身又是字节流,所以可以起到将字节流与字符流“对接”的作用。可以称之为“转换流”。

InputStreamReader 构造方法:

// 该方法有以下几种语法格式:
public InputStreamReader(InputStream in) 
public InputStreamReader(InputStream in, String charsetName)
        throws UnsupportedEncodingException
public InputStreamReader(InputStream in, Charset cs)
public InputStreamReader(InputStream in, CharsetDecoder dec)
复制代码

创建了InputStreamReader对象,就可以使用下面的方法来读取流或者进行其他的流操作:

序号方法及说明
1public String getEncoding(),返回此流正在使用的字符编码的名称
2public int read() throws IOException,读取单个字符并返回读取的字符,如果已到达流的末尾,则返回 -1
3public int read(char cbuf[], int offset, int length) throws IOException,将length数量的字符读入数组并返回读取的字符数,并在数组指定的偏移量开始存储,如果已到达流的末尾,则返回 -1
4public boolean ready() throws IOException,此流是否可以读取。如果输入缓冲区不为空,或者字节可以从底层字节流中读取,则返回true
5public void close() throws IOException{},关闭此输入流并释放与此流有关的所有系统资源。抛出IOException异常

OutputStreamWriter 构造方法:

// 该方法有以下几种语法格式:
public OutputStreamWriter(OutputStream out)
public OutputStreamWriter(OutputStream out, String charsetName)
        throws UnsupportedEncodingException
public OutputStreamWriter(OutputStream out, Charset cs)
public OutputStreamWriter(OutputStream out, CharsetEncoder enc)
复制代码

创建OutputStreamWriter 对象完成后,就可以使用下面的方法来写入流或者进行其他的流操作:

序号方法及说明
1public String getEncoding(),返回此流正在使用的字符编码的名称
2public void write(int c) throws IOException,写入单个字符
3public void write(char cbuf[], int off, int len) throws IOException,在指定的偏移量开始,写入字符数组len长度部分
4public void write(String str, int off, int len) throws IOException,在指定的偏移量开始,写入字符串len长度部分
5void flushBuffer() throws IOException,将输出缓冲区刷新到底层字节流,而不刷新字节流本身
6public void flush() throws IOException,刷新字节流本身
7public void close() throws IOException,关闭此输出流并释放与此流有关的所有系统资源。抛出IOException异常

BufferedInputStream & BufferedOutputStream

缓冲字节流是一对处理流(高级流),可以使我们不再关注必须必须用块读写加快效率,因为缓冲字节流内部维护了一个字节数组,最终会将我们的读写操作转换为块读写,从而加快读写效率。

BufferedInputStream 构造方法:

public BufferedInputStream(InputStream in)
public BufferedInputStream(InputStream in, int size)
复制代码

BufferedOutputStream 构造方法:

public BufferedOutputStream(OutputStream out)
public BufferedOutputStream(OutputStream out, int size)
复制代码

ObjectInputStream & ObjectOutputStream

对象流是一对处理流(高级流),可以方便我们读写 Java 中的任何对象,同城用于序列化。

ObjectInputStream:对象输入流,可以将一组字节还原为对应的对象,前提是这组字节应当是对象输出流将一个对象转换的字节。

ObjectOutputStream:对象输出流,可以将指定的对象转换为一组字节后写出。

File 类

Java文件类以抽象的方式代表文件名和目录路径名。该类主要用于文件和目录的创建、文件的查找和文件的删除等。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) 
复制代码

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

序号方法及说明
1public String getName(),返回由此抽象路径名表示的文件或目录的名称
2public String getParent(),返回此抽象路径名的父路径名的路径名字符串,如果此路径名没有指定父目录,则返回 null
3public File getParentFile(),返回此抽象路径名的父路径名的抽象路径名,如果此路径名没有指定父目录,则返回 null
4public String getPath(),将此抽象路径名转换为一个路径名字符串
5public boolean isAbsolute(),测试此抽象路径名是否为绝对路径名
6public String getAbsolutePath(),返回抽象路径名的绝对路径名字符串
7public boolean canRead(),测试应用程序是否可以读取此抽象路径名表示的文件
8public boolean canWrite(),测试应用程序是否可以修改此抽象路径名表示的文件
9public boolean exists(),测试此抽象路径名表示的文件或目录是否存在
10public boolean isDirectory(),测试此抽象路径名表示的文件是否是一个目录
11public boolean isFile(),测试此抽象路径名表示的文件是否是一个标准文件
12public long lastModified(),返回此抽象路径名表示的文件最后一次被修改的时间
13public long length(),返回由此抽象路径名表示的文件的长度
14public boolean createNewFile() throws IOException,当且仅当不存在具有此抽象路径名指定的名称的文件时,原子地创建由此抽象路径名指定的一个新的空文件
15public boolean delete(),删除此抽象路径名表示的文件或目录
16public void deleteOnExit(),在虚拟机终止时,请求删除此抽象路径名表示的文件或目录
17public String[] list(),返回由此抽象路径名所表示的目录中的文件和目录的名称所组成字符串数组
18public String[] list(FilenameFilter filter),返回由包含在目录中的文件和目录的名称所组成的字符串数组,这一目录是通过满足指定过滤器的抽象路径名来表示的
19public File[] listFiles(),返回一个抽象路径名数组,这些路径名表示此抽象路径名所表示目录中的文件
20public File[] listFiles(FileFilter filter),返回表示此抽象路径名所表示目录中的文件和目录的抽象路径名数组,这些路径名满足特定过滤器
21public boolean mkdir(),创建此抽象路径名指定的目录
22public boolean mkdirs(),创建此抽象路径名指定的目录,包括创建必需但不存在的父目录
23public boolean renameTo(File dest),重新命名此抽象路径名表示的文件
24public boolean setLastModified(long time),设置由此抽象路径名所指定的文件或目录的最后一次修改时间
25public boolean setReadOnly(),标记此抽象路径名指定的文件或目录,以便只可对其进行读操作
26public static File createTempFile(String prefix, String suffix, File directory) throws IOException,在指定目录中创建一个新的空文件,使用给定的前缀和后缀字符串生成其名称
27public static File createTempFile(String prefix, String suffix) throws IOException,在默认临时文件目录中创建一个空文件,使用给定前缀和后缀生成其名称
28public int compareTo(File pathname),按字母顺序比较两个抽象路径名
29public int compareTo(Object o),按字母顺序比较抽象路径名与给定对象
30public boolean equals(Object obj),测试此抽象路径名与给定对象是否相等
31public String toString(),返回此抽象路径名的路径名字符串

Java中的目录

创建目录:File类中有两个方法可以用来创建文件夹:

  • mkdir( )方法创建一个文件夹,成功则返回true,失败则返回false。失败表明File对象指定的路径已经存在,或者由于整个路径还不存在,该文件夹不能被创建。
  • mkdirs()方法创建一个文件夹和它的所有父文件夹。

创建/Users/wanggang/Desktop/bin 文件夹的实例:

mport java.io.File;
 
public class CreateDir {
    public static void main(String[] args) {
        String dirname = "/Users/wanggang/Desktop/bin";
        File d = new File(dirname);
        // 现在创建目录
        d.mkdirs();
    }
}
复制代码

编译并执行上面代码来创建目录 "/Users/wanggang/Desktop/bin"。如图:

注意: Java 在 UNIX 和 Windows 自动按约定分辨文件路径分隔符。如果你在 Windows 版本的 Java 中使用分隔符 (/) ,路径依然能够被正确解析。

读取目录

一个目录其实就是一个 File 对象,它包含其他文件和文件夹。如果创建一个 File 对象并且它是一个目录,那么调用 isDirectory() 方法会返回 true。可以通过调用该对象上的 list() 方法,来提取它包含的文件和文件夹的列表。例如下面展示的例子说明如何使用 list() 方法来检查一个文件夹中包含的内容:

在/Users/wanggang/Desktop/bin文件夹中新建若干文件夹与文件:

import java.io.File;
 
public class DirList {
    public static void main(String args[]) {
        String dirname = "/Users/wanggang/Desktop/bin";
        File f1 = new File(dirname);
        if (f1.isDirectory()) {
            System.out.println("目录 " + dirname);
            String s[] = f1.list();
            for (int i = 0; i < s.length; i++) {
                File f = new File(dirname + "/" + s[I]);
                if (f.isDirectory()) {
                    System.out.println(s[i] + " 是一个目录");
                } else {
                    System.out.println(s[i] + " 是一个文件");
                }
            }
        } else {
            System.out.println(dirname + " 不是一个目录");
        }
    }
}
// 实例编译运行结果如下:
// 目录 /Users/wanggang/Desktop/bin
// demo 是一个目录
// index.html 是一个文件
// .DS_Store 是一个文件
// lib 是一个目录
// test.txt 是一个文件
复制代码

删除目录或文件

删除文件可以使用 java.io.File.delete() 方法。以下代码会删除目录 /Users/wanggang/Desktop/bin,需要注意的是当删除某一目录时,必须保证该目录下没有其他文件才能正确删除,否则将删除失败

删除目录实例:

import java.io.File;
 
public class DeleteFileDemo {
    public static void main(String[] args) {
        // 这里修改为自己的测试目录
        File folder = new File("/Users/wanggang/Desktop/bin");
        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();
    }
}
// 实例编译运行后目录会被删除
  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值