Java进阶篇--IO流的第一篇《输入输出流》

目录

前言

Java File类

Java File类目录

创建目录

列出目录中的文件

Java File类文件

文件的创建与删除

运行可执行文件

Java 文件字节输入流

文件字节输入流构造方法

何使用输入流读取字节以及关闭流

使用输入流读取字节

关闭流

示例代码 

Java 文件字节输出流

文件字节输出流的构造方法 

使用输出流写字节以及关闭流。

使用输出流写字节

关闭流

例如:

Java 文件字符输入输出流


前言

在Java中,输入流用于从外部的数据(如文件、网络连接、内存等)读取数据到程序中,而输出流则用于将程序中的数据输出到外部的目的地(如文件、网络连接、显示器等)。虽然I/O流经常与磁盘文件存取有关,但是源和目的地也可以是键盘、内存或显示器窗口。

输入流和输出流分别通过抽象类InputStream和OutputStream(字节流)以及抽象类Reader和Writer(字符流)来定义。这些抽象类提供了一组通用的方法和功能,可以根据具体的需求选择相应的子类来进行操作。

Java的I/O流库提供了丰富的流类,包括但不限于FileInputStream、FileOutputStream、BufferedReader、BufferedWriter等,可以满足不同场景下的输入输出需求。通过使用Java的输入输出流,我们可以方便地处理各种数据形式,实现数据的读取、写入、复制、传输等操作。这是Java编程中常用的一部分,对于文件处理、网络通信、数据持久化等任务具有重要作用。

Java File类

程序可能经常需要获取磁盘上文件的有关信息或在磁盘上创建新的文件等,这就需要学习使用File类通过File对象,我们可以获取文件的相关信息,如文件路径、文件名、文件长度、读写权限等。File类还提供了一些方法用于判断文件是否存在、创建新文件、删除文件、重命名文件等文件操作。

创建一个File对象的构造方法有三个:

  • File(String pathname):

使用指定路径名创建一个文件或目录的File对象。
该构造方法接受一个字符串参数pathname,用于指定文件或目录的路径。可以是绝对路径或相对路径。如果传入的路径名无效或不存在的文件或目录,则创建的File对象仍然有效,但后续操作可能会失败。

String filePath = "/path/to/file.txt";
File file = new File(filePath);
  • File(String parent, String child):

使用指定的父路径名和子路径名字符串创建一个新的File实例。
该构造方法接受两个字符串参数,parent表示父路径名,child表示子路径名。它们会被拼接起来形成一个完整的路径,用于创建File对象。

String parentPath = "/path/to/";
String fileName = "file.txt";
File file = new File(parentPath, fileName);
  • File(File parent, String child):

从父抽象路径名和子路径名字符串创建一个新的File实例。
该构造方法接受一个File类型的父路径名和一个子路径名字符串参数。它们会根据操作系统的规范进行拼接并创建一个新的File对象。

File parentDir = new File("/path/to/");
String fileName = "file.txt";
File file = new File(parentDir, fileName);

这些构造方法可用于创建File对象,并指定文件或目录的路径。使用不同的参数组合,可以灵活地创建文件和目录的File对象。注意,创建File对象并不会在文件系统中创建实际的文件或目录,它只是一个表示路径的对象。 

File类主要用于文件的元数据(metadata)操作,而不涉及对文件的读写操作。如果需要读取或写入文件内容,需要使用输入输出流(IO流)进行相应的操作。使用File类,我们可以有效地管理文件系统中的文件,并进行必要的文件操作和信息获取。

常用的File类的方法如下:

       方法声明

功能描述

boolean exists()

判断File对象对应的文件或目录是否存在,若存在则返回ture,否则返回false

boolean delete()

删除File对象对应的文件或目录,若成功删除则返回true,否则返回false

boolean createNewFile()

File对象对应的文件不存在时,该方法将新建一个此File对象所指定的新文件,若创建成功则返回true,否则返回false

String getName()

返回File对象表示的文件或文件夹的名称

String getPath()

返回File对象对应的路径

String getAbsolutePath()

返回File对象对应的绝对路径(Unix/Linux等系统上,如果路径是以正斜线/开始,则这个路径是绝对路径;在Windows等系统上,如果路径是从盘符开始,则这个路径是绝对路径)

String getParentFile()

返回File对象对应目录的父目录(即返回的目录不包含最后一级子目录)

String getParent()

返回父目录的路径名。
boolean isHidden() 判断文件是否为隐藏文件。
boolean renameTo(File dest) 将文件或目录重命名为指定的目标路径。

boolean canRead()

判断File对象对应的文件或目录是否可读,若可读则返回true,反之返回false

boolean canWrite()

判断File对象对应的文件或目录是否可写,若可写则返回true,反之返回false

boolean isFile()

判断File对象对应的是否是文件(不是目录),若是文件则返回true,反之返回false

boolean isDirectory()

判断File对象对应的是否是目录(不是文件),若是目录则返回true,反之返回false

boolean isAbsolute()

判断File对象对应的文件或目录是否是绝对路径

boolean mkdir() 创建一个新目录。如果目录已存在或创建失败,则返回false。
boolean mkdirs() 创建一个新目录及其所有必需的父目录。

long lastModified()

返回197011000秒到文件最后修改时间的毫秒值;

long length()

返回文件内容的长度(单位为字节)

String[ ] list()

列出指定目录的全部内容,只是列出名称

File[ ] listFiles()

返回一个包含了File对象所有子文件和子目录的File数组

例如,创建一个名字为new.txt的新文件: 

import java.io.File;
import java.io.IOException;

public class Main {
    public static void main(String args[]) {
        File f = new File("D:\\ch10", "Main.java");
        System.out.println(f.getName() + "是否可读: " + f.canRead());
        System.out.println(f.getName() + "的绝对路径: " + f.getAbsolutePath());

        File file = new File("new.txt");
        System.out.println("在当前目录下创建新文件:" + file.getName());

        try {
            if (!file.exists()) {
                boolean created = file.createNewFile(); // 尝试创建新文件
                if (created) {
                    System.out.println("创建成功");
                } else {
                    System.out.println("创建失败");
                }
            } else {
                System.out.println("文件已存在");
            }
        } catch (IOException exp) {
            exp.printStackTrace();
        }
    }
}

当尝试创建新文件时,使用createNewFile()方法返回的布尔值判断文件是否成功创建。同时,使用异常处理捕获可能抛出的IOException,并打印异常的堆栈信息以便于调试。注意,如果程序没有在指定的路径下或当前目录下具有相应的权限,仍然可能无法成功创建文件。此外,createNewFile()方法只能创建文件,而不能创建目录。如果需要创建目录,可以使用mkdir()或mkdirs()方法。

Java File类目录

创建目录

  1. mkdir():创建一个新目录。如果目录已存在或创建失败,则返回false。
    String dirPath = "/path/to/directory";
    File dir = new File(dirPath);
    boolean success = dir.mkdir();
    if (success) {
        System.out.println("目录创建成功");
    } else {
        System.out.println("目录创建失败");
    }
    
  2. mkdirs():创建一个新目录及其所有必需的父目录。如果目录已存在或创建失败,则返回false。
    String dirPath = "/path/to/new/directory";
    File dir = new File(dirPath);
    boolean success = dir.mkdirs();
    if (success) {
        System.out.println("目录创建成功");
    } else {
        System.out.println("目录创建失败");
    }
    
  3. isDirectory():判断当前File对象是否表示一个目录。
    String path = "/path/to/file.txt";
    File file = new File(path);
    boolean isDirectory = file.isDirectory();
    if (isDirectory) {
        System.out.println("该路径表示一个目录");
    } else {
        System.out.println("该路径不是一个目录");
    }
    

列出目录中的文件

如果File对象表示一个目录,可以使用以下方法来列出该目录下的文件和子目录:

  1. public String[] list():以字符串数组形式返回目录下的所有文件和子目录的名称。
    String dirPath = "/path/to/directory";
    File dir = new File(dirPath);
    String[] files = dir.list();
    for (String fileName : files) {
        System.out.println(fileName);
    }
    
  2. public File[] listFiles():以File对象数组形式返回目录下的所有文件和子目录。
    String dirPath = "/path/to/directory";
    File dir = new File(dirPath);
    File[] files = dir.listFiles();
    for (File file : files) {
        System.out.println(file.getName());
    }
    

有时候,我们需要列出指定类型的文件,比如只列出.java、.txt等特定扩展名的文件。可以使用下述方法来实现:

  1. public String[] list(FilenameFilter filter):以字符串数组形式返回目录下指定类型的文件。
    String dirPath = "/path/to/directory";
    File dir = new File(dirPath);
    
    FilenameFilter filter = new FilenameFilter() {
        @Override
        public boolean accept(File dir, String name) {
            return name.endsWith(".txt");
        }
    };
    
    String[] files = dir.list(filter);
    for (String fileName : files) {
        System.out.println(fileName);
    }
    
  2. public File[] listFiles(FilenameFilter filter):以File对象数组形式返回目录下指定类型的文件。
    String dirPath = "/path/to/directory";
    File dir = new File(dirPath);
    
    FilenameFilter filter = new FilenameFilter() {
        @Override
        public boolean accept(File dir, String name) {
            return name.endsWith(".txt");
        }
    };
    
    File[] files = dir.listFiles(filter);
    for (File file : files) {
        System.out.println(file.getName());
    }
    

 上述两个方法的参数FilenameFilter是一个接口,该接口有一个方法:

public boolean accept(File dir,String name);

File对象dirFile调用list方法时,需向该方法传递一个实现FilenameFilter接口的对象,list方法执行时,参数obj不断回调接口方法accept(File dir,String name),该方法中的参数dir为调用list的当前目录dirFile,参数name被实例化为dirFile目录中的一个文件名,当接口方法返回true时,list方法就将名字为name的文件存放到返回的数组中。

以下是一个Java File类操作目录的示例代码: 

import java.io.File;

public class Main {
    public static void main(String[] args) {
        // 指定目录路径
        String dirPath = "/path/to/directory";

        // 创建File对象表示目录
        File directory = new File(dirPath);

        // 判断File对象是否为目录
        if (directory.isDirectory()) {
            // 列出目录下的所有文件和子目录名称(字符串形式)
            String[] fileNames = directory.list();
            System.out.println("目录下的文件和子目录:");
            for (String fileName : fileNames) {
                System.out.println(fileName);
            }

            System.out.println("----------------");

            // 列出目录下的所有文件和子目录(File对象形式)
            File[] files = directory.listFiles();
            System.out.println("目录下的文件和子目录:");
            for (File file : files) {
                System.out.println(file.getName());
            }
        } else {
            System.out.println("指定的路径不是一个目录。");
        }
    }
}

请注意,你需要将 "/path/to/directory" 替换为实际的目录路径。该示例首先判断指定路径是否为目录,然后使用 list() 方法以字符串数组形式列出目录下的文件和子目录名称,使用 listFiles() 方法以File对象数组形式列出目录下的文件和子目录。

Java File类文件

文件的创建与删除

当使用File类创建一个文件对象后,例如:

File file = new File("C:\\myletter","letter.txt");

如果C:\myletter目录中没有名字为letter.txt文件,文件对象file调用方法: 

public boolean createNewFile();

可以在C:\myletter目录中建立一个名字为letter.txt的文件。文件对象调用方法public boolean delete()可以删除当前文件,例如:

file.delete();

运行可执行文件

当要执行一个本地机器上的可执行文件时,可以使用java.lang包中的Runtime类。首先使用Runtime类声明一个对象:

Runtime ec;

然后使用该类的getRuntime()静态方法创建这个对象:

ec = Runtime.getRuntime();

ec可以调用exec(String command)方法打开本地机器上的可执行文件或执行一个操作。

以下是一个简单的代码示例,展示了File类的一些常见用法: 

import java.io.File;
import java.io.IOException;

public class Main {
    public static void main(String[] args) {
        // 创建一个File对象,指向文件的路径
        File file = new File("example.txt");
        
        try {
            // 判断文件是否存在
            if (file.exists()) {
                System.out.println("文件存在");
                
                // 获取文件名
                System.out.println("文件名:" + file.getName());
                
                // 获取文件路径
                System.out.println("文件路径:" + file.getAbsolutePath());
                
                // 获取文件大小(字节数)
                System.out.println("文件大小:" + file.length() + " 字节");
                
                // 判断是否为文件
                if (file.isFile()) {
                    System.out.println("这是一个文件");
                }
                
                // 判断是否可读、可写、可执行
                System.out.println("可读性:" + file.canRead());
                System.out.println("可写性:" + file.canWrite());
                System.out.println("可执行性:" + file.canExecute());
                
                // 删除文件
                boolean deleted = file.delete();
                if (deleted) {
                    System.out.println("文件删除成功");
                } else {
                    System.out.println("文件删除失败");
                }
            } else {
                System.out.println("文件不存在");
                
                // 创建新文件
                boolean created = file.createNewFile();
                if (created) {
                    System.out.println("文件创建成功");
                } else {
                    System.out.println("文件创建失败");
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

请注意,上述代码仅演示了File类的一些基本用法,如判断文件是否存在、获取文件信息、创建和删除文件等操作。实际使用时,还可以使用File类的其他方法来进行更复杂的文件操作,例如文件重命名、文件夹操作等。

Java 文件字节输入流

文件字节输入流构造方法

使用输入流通常包括4个基本步骤:

  1. 设定输入流的源
  2. 创建指向源的输入流
  3. 让输入流读取源中的数据
  4. 关闭输入流,释放系统资源。

如果对文件读取需求比较简单,那么可以使用FileInputStream类(文件字节输入流),该类是InputStream类的子类(以字节为单位读取文件),该类的实例方法都是从InputStream类继承来的。

FileInputStream(String name);
FileInputStream(File file);

第一个构造方法使用给定的文件名name创建FileInputStream流;第二个构造方法使用File对象创建FileInputStream流。参数name和file指定的文件称为输入流的源。

FileInputStream输入流打开一个到达文件的通道(源就是这个文件,输入流指向这个文件)。当创建输入流时,可能会出现错误(也被称为异常)。例如,输入流指向的文件可能不存在。当出现I/O错误,Java生成一个出错信号,它使用IOException(IO异常)对象来表示这个出错信号。程序必须在try-catch语句中的try块部分创建输入流,在catch块部分检测并处理这个异常。

何使用输入流读取字节以及关闭流

我们已经学习了文件字节输入流的构造方法,接下来我们继续学习如何使用输入流读取字节以及关闭流。 

使用输入流读取字节

输入流的目的是提供读取源中数据的通道,程序可以通过这个通道读取源中的数据,文件字节流可以调用从父类继承的read方法顺序地读取文件,只要不关闭流,每次调用read方法就顺序地读取文件中的其余内容,直到文件的末尾或文件字节输入流被关闭。

字节输入流的read方法以字节为单位读取源中的数据。

  1. int read():输入流调用该方法从源中读取单个字节的数据,该方法返回字节值(0~255之间的一个整数),如果未读出字节就返回-1。
  2. int read(byte b[ ]):输入流调用该方法从源中试图读取b.length个字节到字节数组b中,返回实际读取的字节数目。如果到达文件的末尾,则返回-1。
  3. int read(byte b[],int off,int len):输入流调用该方法从源中试图读取len个字节到字节数组b中,并返回实际读取的字节数目。如果到达文件的末尾,则返回-1,参数off指定从字节数组的某个位置开始存放读取的数据。

注意:FileInputStream流顺序地读取文件,只要不关闭流,每次调用read方法就顺序地读取源中其余的内容,直到源的末尾或流被关闭。

关闭流

输入流都提供了关闭方法close(),尽管程序结束时会自动关闭所有打开的流,但是当程序使用完流后,显示地关闭任何打开的流仍是一个良好的习惯。如果没有关闭那些被打开的流,那么就可能不允许另一个程序操作这些流所用的资源。

示例代码 

以下是一个简单的示例代码:

import java.io.FileInputStream;
import java.io.IOException;

public class Main {
    public static void main(String[] args) {
        FileInputStream fis = null;
        try {
            // 创建FileInputStream对象
            fis = new FileInputStream("new.txt");

            // 创建byte数组
            byte[] buffer = new byte[1024];

            // 读取字节数据
            int bytesRead;
            while ((bytesRead = fis.read(buffer)) != -1) {
                // 处理读取的字节数据
                // 这里可以根据实际需求进行处理,比如写入其他文件或进行数据处理等

                // 示例:将读取的字节数据转换为字符串并打印输出
                String data = new String(buffer, 0, bytesRead);
                System.out.println(data);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                // 关闭输入流
                if (fis != null) {
                    fis.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

Java 文件字节输出流

文件字节输出流的构造方法 

使用输出流通常包括4个基本步骤:

  1. 给出输出流的目的地

  2. 创建指向目的地的输出流

  3. 让输出流把数据写入到目的地

  4. 关闭输出流

如果对文件写入需求比较简单,那么可以使用FileOutputStream类(文件字节输出流),它是OutputStream类的子类(以字节为单位向文件写入内容),该类的实例方法都是从OutputStream类继承来的。

我们可以使用FileOutputStream类的下列具有刷新功能的构造方法创建指向文件的输出流。

FileOutputStream(String name);
FileOutputStream(File file);

第一个构造方法使用给定的文件名name创建FileOutputStream流;第二个构造方法使用File对象创建FileOutputStream流。参数name和file指定的文件称为输出流的目的地。

FileOutputStream输出流开通一个到达文件的通道(目的地就是这个文件,输出流指向这个文件)。

注意:如果输出流指向的文件不存在,Java就会创建该文件,如果指向的文件是已存在的文件,输出流将刷新该文件(使得文件的长度为0)。

除此之外,与创建输入流相同的是,创建输出流时,可能会出现错误(被称为异常),例如,输出流试图要写入的文件可能不允许操作或有其他受限等原因。所以必须在try-catch语句中的try块部分创建输出流,在catch块部分检测并处理这个异常。

例如,创建指向名为destin.txt的输出流out:

try {
    FileOutputStream out = new FileoutputStream("destin.txt"); //创建指向文件destin.txt的输出流
}
catch(IOException e) {
    System.out.println("File write error:"+e);
}

File f = new File("destin.txt"); //指定输出流的目的地
try {
    FileOutputStream out = new FileOutputStream(f); //创建指向目的地的输出流
}
catch(IOException e) {
    System.out.println("Filewrite:"+e);
}

我们可以使用FileOutputStream类的下列能选择是否具有刷新功能的构造方法创建指向文件的输出流。

FileOutputStream(String name,boolean append);
FileOutputStream(File file,boolean append);

当用构造方法创建指向一个文件的输出流时,如果参数append取值true,输出流不会刷新所指向的文件(假如文件已存在),输出流的write的方法将从文件的末尾开始向文件写入数据,参数append取值false,输出流将刷新所指向的文件(假如文件已经存在)。

使用输出流写字节以及关闭流。

我们已经学习了文件字节输出流的构造方法,接下来我们继续学习如何使用输出流写字节以及关闭流。

使用输出流写字节

输出流的目的是提供通往目的地的通道,程序可以通过这个通道将程序中的数据写入到目的地,文件字节流可以调用从父类继承的write方法顺序地写文件。FileOutStream流顺序地向文件写入内容,即只要不关闭流,每次调用write方法就顺序地向文件写入内容,直到流被关闭。

字节输出流的write方法以字节为单位向目的地写数据。

  1. void write(int n):输出流调用该方法向目的地写入单个字节。
  2. void write(byte b[ ]):输出流调用该方法向目的地写入一个字节数组。
  3. void write(byte b[ ],int off,int len):给定字节数组中起始于偏移量off处取len个字节写到目的地。
  4. void close():关闭输出流。

注意:FileOutputStream流顺序地写文件,只要不关闭流,每次调用write方法就顺序地向目的地写入内容,直到流被关闭。

关闭流

在操作系统把程序所写到输出流上的那些字节保存到磁盘上之前,有时被存放在内存缓冲区中,通过调用close()方法,可以保证操作系统把流缓冲区的内容写到它的目的地,即关闭输出流可以把该流所用的缓冲区的内容冲洗掉,通常冲洗到磁盘文件上。

例如:

import java.io.*;

public class Main {
    public static void main(String args[]) {
        byte [] a = "新年快乐".getBytes();
        String [] str = {"Hello", "World"};
        File file = new File("output.txt"); // 输出的目的地

        try {
            // 写入字节数组
            OutputStream out = new FileOutputStream(file);
            System.out.println(file.getName() + "的大小:" + file.length() + "字节");
            out.write(a);
            out.close();

            // 写入字符串数组
            out = new FileOutputStream(file, true);
            System.out.println(file.getName() + "的大小:" + file.length() + "字节");
            for (String s : str) {
                out.write(s.getBytes());
            }
            System.out.println(file.getName() + "的大小:" + file.length() + "字节");
            out.close();

            // 写入字符串
            String line = "这是另一行。";
            out = new FileOutputStream(file, true);
            System.out.println(file.getName() + "的大小:" + file.length() + "字节");
            out.write(line.getBytes());
            System.out.println(file.getName() + "的大小:" + file.length() + "字节");
            out.close();
        } catch (IOException e) {
            System.out.println("Error" + e);
        }
    }
}

这个示例向名为 "output.txt" 的文件中写入了不同类型的数据:字节数组、字符串数组、字符串和换行符。请注意,如果文件不存在,FileOutputStream 将创建一个新文件。如果文件已经存在,它将清空文件内容,然后开始写入。

Java 文件字符输入输出流

文件字节输入输出流的read和write方法使用字节数组读写数据,即以字节为单位处理数据。因此,字节流不能很好地操作Unicode字符。比如,一个汉字在文件中占用2个字节,如果使用字节流,读取不当会出现“乱码”现象。

与FileInputStream、FileOutputStream字节流相对应的是FileReader、FileWriter字符流(文件字符输入、输出流),FileReader和FileWriter分别是Reader和Writer的子类,其构造方法分别是:

FileReader(String filename);FileReader(File filename);
Fi1eWriter(String filename);FileWriter(File filename);
FileWriter(String filename,boolean append);FileWriter(File filename,boolean append);

字符输入流和输出流的read和write方法使用字符数组读写数据,即以字符为基本单位处理数据。

例如: 

import java.io.*;
public class Main {
    public static void main(String args[]) {
        File sourceFile = new File("a.txt"); //读取的文件
        File targetFile = new File("b.txt"); //写入的文件
        char c[] = new char[19]; //char型数组
        try {
            Writer out = new FileWriter(targetFile,true); //指向目的地的输出流
            Reader in = new FileReader(sourceFile); //指向源的输入流
            int n = -1;
            while((n = in.read(c)) !=-1) {
                out.write(c,0,n);
            }
            out.flush(); // 在将StringBuilder的内容写入文件后调用flush()方法,以确保数据被立即写入文件
            out.close();
        }
        catch(IOException e) {
            System.out.println("Error"+e);
        }
    }
}

注意:对于Writer流,write方法将数据首先写入到缓冲区,每当缓冲区溢出时,缓冲区的内容被自动写入到目的地,如果关闭流,缓冲区的内容会立刻被写入到目的地。流调用flush()方法可以立刻冲洗当前缓冲区,即将当前缓冲区的内容写入到目的地。

你可能感兴趣的:(Java进阶篇,java,开发语言)