diff --git a/05:IO编程/01.md b/05:IO编程/01.md index e69de29..7bd6880 100644 --- a/05:IO编程/01.md +++ b/05:IO编程/01.md @@ -0,0 +1,244 @@ +> The File class is intended to provide an abstraction that deals with most of the machine-dependent complexities of files and path names in a machine-independent fashion. The filename is a string. The File class is a wrapper class for the file name and its directory path. +> +> 文件类提供了一个与机器(操作系统)无关的文件和路径操作的封装;文件类主要用作文件名和路径的操作,并不对文件本生的内容进行操作。 + +注意: + +1. 在文件系统中有路径的概念,路径的分隔符是“/”叫做斜杠;Windows系统中的文件分割符与其他的操作系统是相反的“\”反斜杠,这可能会造成一些困扰,最典型的就是字符串转义。在所有的语言中,反斜杠(\)被用作字符串的转义字符,例如“\n”代表换行,“\t”代表tab等。在Java编程当中,凡是遇到路径分割符的地方,只需要使用斜杠“/”就可以了,Java会根据运行的操作系统自动进行转换和处理。例如:“C:/windows/cfg.ini”,最好不要使用反斜杠,如果需要反斜扛,需要这样写:“C:\\\windows\\\cfg.ini”,因为反斜杠在字符串中代表转义。 +2. 你们会发现,在URL,例如“http://www.baidu.com/qurey/index.html”,这样的字符串中,斜杠也是路径分隔符,因此斜杠在大多数情况下都是通用的,尽量不要用反斜杠代表路径分割。 +3. Windows文件系统具有盘符的概念,在其他大多文件系统中是没有这个概念的。例如Linux中,一个逻辑盘可以被分配到一个目录当中,linux的文件系统是从"/"开始的,叫做根-root。 +4. Windows文件系统中,文件名是不区分大小写的;在其他多数文件系统中文件名是区分大小写的(case sensitive),这一点需要特别注意。 + +## 1. 文件类 + +![image-20230324144051355](img/image-20230324144051355.png) + +文件类是一个对文件名和路径操作的类。可以进行如下操作: + +1. 文件是否存在; +2. 是否可读; +3. 是否可写; +4. 是否是目录(目录是特殊的文件); +5. 是否是文件; +6. 是否是绝对路径; +7. 是否隐藏文件; +8. 得到文件的绝对路径; +9. 文件修改和范围时间; +10. 文件重命名; +11. 新建目录; +12. 目录列表 +13. ... + +### 1.1. 读取文件属性 + +注意第一行的包引入。 + +```java +import java.io.File; + +public class TestFileClass { + public static void main(String[] args) { + File file = new File("src/TestFileClass.java"); + System.out.println("Does it exist? " + file.exists()); + System.out.println("The file has " + file.length() + " bytes"); + System.out.println("Can it be read? " + file.canRead()); + System.out.println("Can it be written? " + file.canWrite()); + System.out.println("Is it a directory? " + file.isDirectory()); + System.out.println("Is it a file? " + file.isFile()); + System.out.println("Is it absolute? " + file.isAbsolute()); + System.out.println("Is it hidden? " + file.isHidden()); + System.out.println("Absolute path is " + file.getAbsolutePath()); + System.out.println("Last modified on " + new java.util.Date(file.lastModified())); + } +} +``` + +构造参数传的字符串代表一个文件,注意这里使用的是相对路径(也可以是绝对路径)。其实也可以是一个文件夹的路径,在操作系统中,文件夹是一种特殊的文件。我们可以看到,file这个对象其实是一个文件,可以对文件的属性进行读取。 + +这里不对File类的所有功能进行分析,以后很多情况下,需要用一个File对象作为参数。大多时候,这个File对象代表对应的文件。 + +## 2. 文本文件操作 + +> A File object encapsulates the properties of a file or a path, but does not contain the methods for reading/writing data from/to a file. In order to perform I/O, you need to create objects using appropriate Java I/O classes. The objects contain the methods for reading/writing data from/to a file. This section introduces how to read/write strings and numeric values from/to a text file using the Scanner and PrintWriter classes. +> +> File 对象封装了对文件名和路径的操作,但是不对文件的具体内容进行读写。为了完成I/O(文件输入输出)操作,需要使用适当的I/O操作类。这些I/O操作类具有读写文件的能力。这一节,我们介绍使用Scanner和PrintWriter类对文本文件中的字符串进行操作。 + + + +### 2.1. PrintWrite类 + +![image-20230324145547079](img/image-20230324145547079.png) + +可以看到,PrintWrite如同一个打印机,向文件打印不同类型的数据(这些数据被转换成字符串的方式,而不是二进制的方式)。该类也有println和printf函数,和前面讲的控制台输出函数是一样的,只不过不是控制台输出,而是输出到文件。注意操作系统不一样,回车换行字符不一样;Windows是`\r\n`,linux是`\n`。 + +```java +import java.io.File; +import java.io.PrintWriter; + +public class WriteData { + public static void main(String[] args) throws Exception { + File file = new java.io.File("D:/scores.txt"); + if (file.exists()) { + System.out.println("File already exists"); + System.exit(1); + } + + // Create a file + PrintWriter output = new PrintWriter(file); + + // Write formatted output to the file + output.print("John T Smith "); + output.println(90); + output.print("Eric K Jones "); + output.println(85); + + // Close the file + output.close(); + } +} +``` + +1. 首先建立了一个File对象,其文件名是`D:/scores.txt`;判断文件是否存在,如果存在,退出出返回1。 +2. 如果不存在,建立一个PrintWriter的对象ouput,其构造函数的参数正式前面的File对象,代表向哪个文件进行操作。PrintWriter的构造函数有多个,可以接受一个字符串代表文件名,也可以接受一个File对象代表文件。 +3. 后面就是日常的操作了,看看结果。 +4. 别忘了,文件操作完成后,需要关闭PrintWriter。 + +``` +John T Smith 90 +Eric K Jones 85 +``` + +**注意:File对象没有close()方法,因为File对象不对文件的具体内容进行操作。** + +主函数是有返回值的,返回一个整数;对于多数操作系统来说,返回值代表程序是否运行成功;一般返回值是0代表成功,没有错误;非零代表有错误。 + +### 2.2. 不要别忘记关闭文件 + +和C一样,文件用完后需要关闭。因为文件属于共享I/O资源,可能有多个程序对同一文件进行操作,如果忘记关闭将出现很多意想不到的问题。Java提供了一个语法结构来保证文件总是被正确关闭。 + +```java +public class WriteDataWithAutoClose { + public static void main(String[] args) throws Exception { + java.io.File file = new java.io.File("scores.txt"); + if (file.exists()) { + System.out.println("File already exists"); + System.exit(0); + } + + try ( + // Create a file + java.io.PrintWriter output = new java.io.PrintWriter(file); + + ) { + // Write formatted output to the file + output.print("John T Smith "); + output.println(90); + output.print("Eric K Jones "); + output.println(85); + } + } +} +``` + +注意上面的的语法结构,try后面是一个括号,这个括号中可以有多条语句(上述只有一条);而且这个用小括号包裹的语法块不是所有的语句都可以写的,只能是构造对象的语法,而且对象必须实现了`Closeable`这个接口。 + +```java +public class PrintWriter extends Writer {...} +public abstract class Writer implements Appendable, Closeable, Flushable {...} +``` + +PrinterWriter 从抽象类Writer扩展;Writer这个类实现了Closeable这个接口。 + +**因此:try语法块中小括号包含的语句必须是实现了Closeable接口的对象构造语句。** + +后面大括号内包含的语法块就好理解了,就是说这里的语句再执行完成后,不需要关闭小括号中语句打开的资源,Java会自动关闭。 + +### 2.3. Scanner可以读取文件 + +还记得以前学过的Scanner对象,从控制台读取数据吗? + +```java +Scanner scanner = new Scanner(System.in); +``` + +构造函数的参数是`System.in`表示从标准输入读取(看具体定义,一般是控制台);如果把这个参数换成是File对象,就可以从文本文件读取了。 + +```java +import java.util.Scanner; + +public class ReadData { + public static void main(String[] args) throws Exception { + // Create a File instance + java.io.File file = new java.io.File("d:/scores.txt"); + + // Create a Scanner for the file + Scanner input = new Scanner(file); + + // Read data from a file + while (input.hasNext()) { + String firstName = input.next(); + String mi = input.next(); + String lastName = input.next(); + int score = input.nextInt(); + System.out.println(firstName + " " + mi + " " + lastName + " " + score); + } + + // Close the file + input.close(); + } +} +``` + +注意:这时就需要使用close()来关闭Scanner对象了,因为这里的input是对文件I/O进行操作。 + +你可以尝试使用`try(...){...}`的语法结构来自动关闭Scanner对象,因为Scanner也是实现了Closeable的接口。 + +### 2.4. 从url读取数据 + +WEB上的文件(HTML)也是文件,因此也可以读取,不过需要连接到互联网。 + +![image-20230324154720491](img/image-20230324154720491.png) + +```java +import java.util.Scanner; + +public class ReadFileFromURL { + public static void main(String[] args) { + System.out.print("Enter a URL: "); + String URLString = new Scanner(System.in).next(); // 从控制台读取URL + + try { + java.net.URL url = new java.net.URL(URLString); // 建立一个URL对象,输入参数是刚刚读取的URL字符串 + int count = 0; + Scanner input = new Scanner(url.openStream()); // 这里是流编程,url.openStream 返回一个InputStream对象 + while (input.hasNext()) { // 这里就一样了 + String line = input.nextLine(); + count += line.length(); + System.out.println(line); + } + + System.out.println("The file size is " + count + " bytes"); + } catch (java.net.MalformedURLException ex) { + System.out.println("Invalid URL"); + } catch (java.io.IOException ex) { + System.out.println("IO Errors"); + } + } +} +``` + +## 3. 重点 + +1. 掌握File类的基本使用; +2. 掌握PrintWriter的基本使用; +3. 掌握Scnner读取文本文件内容的基本使用; +4. 了解 try(...){...}语法; + + + + + + + + + diff --git a/05:IO编程/img/image-20230324144051355.png b/05:IO编程/img/image-20230324144051355.png new file mode 100644 index 0000000..716f804 Binary files /dev/null and b/05:IO编程/img/image-20230324144051355.png differ diff --git a/05:IO编程/img/image-20230324145547079.png b/05:IO编程/img/image-20230324145547079.png new file mode 100644 index 0000000..e12f530 Binary files /dev/null and b/05:IO编程/img/image-20230324145547079.png differ diff --git a/05:IO编程/img/image-20230324154720491.png b/05:IO编程/img/image-20230324154720491.png new file mode 100644 index 0000000..b1bc304 Binary files /dev/null and b/05:IO编程/img/image-20230324154720491.png differ