从控制台读写数据。在 java.io 包中使用BufferedReader、BufferedWriter、File、fileereader、FileWriter、FileInputStream、FileOutputStream、ObjectOutputStream、ObjectInputStream和PrintWriter。
- I/O Streams
- File
- 了解java.io包
- FileInputStream
- FileOutputStream
- FileReader
- FileWriter
- BufferedReader
- BufferedWriter
- ObjectInputStream/ ObjectOutputStream
- PrintWriter
- Standard streams
- java.io.Console
- 总结
I/O Streams
I/O流和Stream API 没有任何关系。
简单地说,流就是一系列的数据。
- 当我们从一个文件中读取这个字节序列时,我们正在读取一个输入流。
- 当我们将这个字节序列写入一个文件时,就是在写入一个输出流。
- 文件的内容可能非常大,以至于可能无法放入内存,因此在处理流时,我们不能一次性关注整个流,而是在任何时候都只关注一小部分(逐字节或一组字节)
- java.io 包中,我们可以找到处理字节流和字符流的类
File
把文件看作存储数据的资源(以字节或字符格式)。文件组织在目录中,除了文件,还可以包含其他目录。
文件或目录可以用一个名为 path 的 String 表示,其中分隔符字符左侧的值(在文件系统之间更改)是分隔符右侧值的父元素,如/home/documents/file.txt 或 Windows 上的c:\home\documents\file.txt
File file = new File("/home/user.properties");
有了一个 File 对象,可以使用一些方法来处理这个文件/目录
String path = ...
File file = new File(path);
if(file.exists()) {
// Name of the file/directory
String name = file.getName();
// Path of its parent
String parent = file.getParent();
// Returning the time the file/directory was modified
// in milliseconds since 00:00:00 GMT, January 1, 1970
long millis = file.lastModified();
// If the object represents a file
if(file.isFile()) {
// Returning the size of the file in bytes
long size = file.length();
}
// If the object represents a directory
else if(file.isDirectory()) {
// Returns true only if the directory was created
boolean dirCreated = file.mkdir();
// Returns true only if the directory was created,
// along with all necessary parent directories
boolean dirsCreated = file.mkdirs();
// Get all the files/directories in a directory
// Just the names
String[] fileNames = file.list();
// As File instances
File[] files = file.listFiles();
}
boolean wasRenamed = file.renameTo(new File("new file"));
boolean wasDeleted = file.delete();
}
常用API
由于其API非常多,只是列举一些
- getName()
这只是路径名名称序列中的最后一个名称。 如果路径名的名称序列为空,则返回空字符串。 - exists()
此抽象路径名表示的文件或目录是否存在 - getParent()
返回此抽象路径名的父目录的路径名字符串,如果此路径名未命名父目录,则返回null - isFile()
当且仅当此抽象路径名表示的文件存在并且是普通文件时才为true ; 否则为false - isDirectory()
当且仅当此抽象路径名表示的文件存在并且是目录时才为true ; 否则为false - file.mkdir()
创建由此抽象路径名命名的目录 - mkdirs()
当且仅当创建了目录以及所有必需的父目录时才为true ; 否则为false - delete()
删除此抽象路径名表示的文件或目录。 如果此路径名表示一个目录,则该目录必须为空才能被删除 - list()
其只会列举出当前目录(如果不为目录则返回null)的子集文件和目录名字,不包含其他任何路径和更深层次的目录。
了解java.io包
java.io 包中有很多类,OCP涉及到的类中4个抽象abstract类是其他类的父类
- 字节流byte Stream
1.InputStream
2.OutputStream - 字符流character Stream
1.Reader
2.Writer
其都实现了 AutoClosable,因此可以在 try-with-resources 中使用。不必手动finally释放资源
规则分类
- Input 或 Reader 的类用于read(字节或字符)
- Output 和 Writer 的所有类都是为了writer(字节或字符)
- Buffered 的类,它们使用缓冲区以组(字节或字符)的形式读写数据
- 可以进一步将 API 中的类分为包装器和非包装器。
1.非包装类通常使用 File 或 String 的实例来创建实例
2.包装类使用另一个流类来创建实例。
//包装类
try {
ObjectInputStream ois =
new ObjectInputStream(new FileInputStream("obj.dat"));
} catch (IOException e) {
e.printStackTrace();
}
- 使用包装类不能将字节流和字符流混合
FileInputStream
从文件中读取字节。继承InputStream抽象类
常用API
- read()
- 从此输入流中读取一个字节的数据。 如果尚无可用输入,则此方法会阻塞。
返回值:数据的下一个字节,如果到达文件末尾,则为-1 。 - read(byte b[])
从此输入流中读取最多b.length个字节的数据到一个字节数组中。 此方法会阻塞,直到某些输入可用。
参数:b – 读取数据的缓冲区。
返回值:读入缓冲区的总字节数,如果由于已到达文件末尾而没有更多数据,则为-1 。 - skip(long n)
跳过并丢弃输入流中的n字节数据。
创建实例
1.构造方法
//,此处没有fianlly的close,因为ObjectInputStream实现了 AutoClosable,且在 try-with-resources 中使用
try (InputStream in = new FileInputStream("c:\\file.txt")) {
int b;
// -1 indicates the end of the file
while((b = in.read()) != -1) {
// Do something with the byte read
}
} catch(IOException e) { /** ... */ }
也可以使用数组将信息读入
try (InputStream in = new FileInputStream("c:\\file.txt")) {
byte[] data = new byte[1024];
int numberOfBytesRead;
while ((numberOfBytesRead = in.read(data)) != -1) {
// Do something with the array data
}
} catch (IOException e) { /** ... */}
}
FileOutputStream
将字节写入文件中。继承OutputStream抽象类
常用API
- FileOutputStream(String name)
如果文件存在但是是一个目录而不是常规文件,不存在但无法创建,或者由于任何其他原因无法打开,则抛出FileNotFoundException - write(int b)
将指定字节写入此文件输出流。 实现OutputStream的write方法。
参数:b – 要写入的字节。 - void write(byte b[])
将指定字节数组中的b.length个字节写入此文件输出流。
参数:b——数据
创建实例
1.构造方法
try (OutputStream out =
new FileOutputStream("c:\\file.txt")) {
int b;
// Made up method to get some data
while((b = getData()) != -1) {
// Writes b to the file output stream
out.write(b);
out.flush();
}
} catch(IOException e) { /** ... */ }
刷新推送
写入 OutputStream 时,数据可能被内部缓存在内存中,稍后写入磁盘。如果希望确保所有数据都写入磁盘而不必关闭 OutputStream,可以每隔一段时间调用 flush ()方法
close时会flush
FileReader
从文本文件读取字符。继承抽象类Reader
其只是读取字符文件的便利类,只是多了几个构造方法而已
创建实例
try (Reader r = new FileReader("/file.txt")) {
int c;
// -1 indicates the end of the file
while((c = r.read()) != -1) {
char character = (char)c;
// Do something with the character
}
} catch(IOException e) { /** ... */ }
FileWriter
FileWriter 将字符写入文本文件。继承 Writer抽象类
创建实例
try (Writer w = new FileWriter("/file.txt")) {
w.write('-'); // writing a character
// writing a string
w.write("Writing to the file...");
} catch(IOException e) { /** ... */ }
推送流
数据可能被内部缓存在内存中,稍后写入磁盘。如果希望确保所有数据都写入磁盘而不必关闭 FileWriter,可以每隔一段时间调用 flush ()方法
BufferedReader
从字符流中读取文本。一次将一个大块读取到缓冲区中。继承Reader抽象类
这是一个包装类,通过传递一个 Reader 到它的构造函数,并且可以选择传递缓冲区的大小来创建
BufferedReader(Reader in)
BufferedReader(Reader in, int size)
try ( BufferedReader br =
new BufferedReader( new FileReader("/file.txt") ) ) {
String line;
// null indicates the end of the file
while((line = br.readLine()) != null) {
// Do something with the line
}
} catch(IOException e) { /** ... */ }
当 BufferedReader 关闭时,它还将关闭它从中读取的 Reader 实例。(即不必调用Reader的close方法)
BufferedWriter
将文本写入字符流,缓冲字符以提高效率。
也为包装类
创建实例
BufferedWriter(Writer out)
BufferedWriter(Writer out, int size)
try ( BufferedWriter bw =
new BufferedWriter( new FileWriter("/file.txt") ) ) {
w.write("Writing to the file...");
w.newLine();
} catch(IOException e) { /** ... */ }
刷新推送
数据首先被写入缓冲区,可以调用 flush ()方法来确保在此之前写入的文本确实被写入到磁盘中。
BufferedWriter 关闭时,它也会关闭它所写入的 Writer 实例
ObjectInputStream/ ObjectOutputStream
- ObjectOutputStream 允许将对象序列化到 OutputStream
- ObjectInputStream 允许从 InputStream 反序列化对象。所以两者都被认为是包装器类。
序列化和反序列化
- 对象转换为可以存储的数据格式(例如文件)的过程称为序列化
- 将存储的数据格式转换为对象的过程称为反序列化
序列化
要序列化一个对象,它的类必须实现 java.io. Serializable。它没有方法来实现,它只是将该类的对象标记为可序列化的。
如果序列化一个不实现该接口的类,则java.io.NotSerializableException (IOException 的子类)将在运行时抛出。
Seriable接口仅仅是个标识,检查obj除了为String、enum枚举、数组之外的类时是否实现Seriable,为否则抛出NotSerializableException异常
ObjectOutputStream
- 创建实例
其构造方法public只有一个
ObjectOutputStream(OutputStream out)
class Box implements java.io.Serializable {
/** ... */
}
...
try( ObjectOutputStream oos =
new ObjectOutputStream(
new FileOutputStream("obj.dat") ) ) {
Box box = new Box();
oos.writeObject(box);
} catch(IOException e) { /** ... */ }
ObjectInputStream
反序列化文件 obj.dat,使用 ObjectInputStream 类
Object readObject()
throws IOException, ClassNotFoundException
它返回一个 Object 类型。必须显式地强制转换对象。这可能导致在运行时抛出 ClassCastException(非检查异常)。如果找不到序列化对象的类,此方法还抛出 ClassNotFoundException (一个检查过的异常)
try (ObjectInputStream ois =
new ObjectInputStream(
new FileInputStream("obj.dat") ) ) {
Box box = null;
Object obj = ois.readObject();
if(obj instanceof Box) {
box = (Box)obj;
}
} catch(IOException ioe) { /** ... */ }
catch(ClassNotFoundException cnfe) {
/** ... */
}
PrintWriter
Writer抽象类的子类,将格式化的数据写入另一个(包装的)流,甚至是 OutputStream。
// Opens or creates the file without automatic line flushing
// and converting characters by using the default character encoding
try(PrintWriter pw = new PrintWriter("/file.txt")) {
pw.write("Hi"); // Writing a String
pw.write(100); // Writing a character
// write the string representation of the argument
// it has versions for all primitives, char[], String, and Object
pw.print(true);
pw.print(10);
// same as print() but it also writes a line break as defined by
// System.getProperty("line.separator") after the value
pw.println(); // Just writes a new line
pw.println("A new line...");
// format() and printf() are the same methods
// They write a formatted string using a format string,
// its arguments and an optional Locale
pw.format("%s %d", "Formatted string ", 1);
pw.printf("%s %d", "Formatted string ", 2);
pw.format(Locale.GERMAN, "%.2f", 3.1416);
pw.printf(Locale.GERMAN, "%.3f", 3.1416);
} catch(FileNotFoundException e) {
// if the file cannot be opened or created
}
Standard streams
Java初始化并提供三个流对象作为Java.lang.System类的公共静态字段
- InputStream System.in
标准输入流(通常是键盘输入) - PrintStream System.out
标准输出流(通常是默认的显示输出) - PrintStream System.err
标准错误输出流(通常是默认的显示输出)
PrintStream的功能和 PrintWriter 完全一样,但只能使用 OutputStreams
读取命令行字符
- int
System.out.print("Enter a character: ");
try {
int c = System.in.read();
} catch(IOException e) {
System.err.println("Error: " + e);
}
- String
BufferedReader br =
new BufferedReader(new InputStreamReader(System.in));
String line = br.readLine();
// Or using the java.util.Scanner class
Scanner scanner = new Scanner(System.in);
String line = scanner.nextLine();
java.io.Console
单例
java.io.Console 类来访问程序运行所在机器的控制台。
System.console()方法获得单例
最终还是通过JavaIOAccess接口的console()方法得到的
Console console1 = System.console();
JavaIOAccess javaIOAccess = SharedSecrets.getJavaIOAccess();
Console console = javaIOAccess.console();
System.out.println(console==console1);
- 程序运行在无法访问控制台的环境中(如 IDE 或者如果您的程序作为后台进程运行) ,System.console ()将返回 null
- 使用 readLine ()方法读取用户输入,使用 readPassword ()读取密码。
- Reader ()和 Writer ()分别返回一个 Reader 和 Writer 的实例
Console console = System.console();
// Check if the console is available
if(console != null) {
console.writer().println("Enter your user and password");
String user = console.readLine("Enter user: ");
// readPassword() hides what the user is typing
char[] pass = console.readPassword("Password: ");
// Clear password from memory by overwriting it
Arrays.fill(pass, 'x');
}
总结
- I/O流是表示文件内容的数据序列。
- 有四个主要的抽象类,其余的类从InputStream、OutputStream、Reader和Writer扩展而来。
- java.io类可分为:
1.字节流或字符流
2.输入或输出
3.包装或非包装 - Java初始化并提供三个流对象作为Java.lang.System类的公共静态字段:
1.InputStream System.in标准输入流(通常是来自键盘的输入)
2.PrintStream System.out标准输出流(通常是默认的显示输出)
3.PrintStream System.err标准错误输出流(通常是默认的显示输出)Z
Comments | 0 条评论