- 1 File类
- 2 输入和输出
- 3 添加属性和有用的接口
- 4 Reader和Writer
- 5 自我独立的类RandomAccessFile
- 6 I/O流的典型使用方式
- 7 文件读写的使用工具
- 8 标准I/O
- 9 进程控制
- 10 新I/O复习时候再review补
- 11 压缩
- 12 对象序列化
- 13 XML
- 14 Preferences
- 15 总结
1 File类
File这个名字并非指代文件,它既能代表一个特定的文件,又能代表一个目录下的文件集合。如果指代的是文件集合的话,可以调用list()方法得到一个包含该目录下文件集合的数组。
1.1 目录列表器
查看一个目录列表,有两种方法:
1.调用不带参数的list()获取全部文件的集合
2.使用“目录过滤器”获得符合条件的文件集合
package io;
import java.io.File;
import java.io.FilenameFilter;
import java.util.Arrays;
import java.util.regex.Pattern;
// args: .*\.java
public class DirList {
public static void main(String[] args) {
// File path = new File(".");
File path = new File("/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io");
String[] list;
if (args.length== 0)
list = path.list();//指定目录的全部列表
else
list = path.list(new DirFilter(args[0]));//指定目录的受限列表,使用FilenameFilter 筛选器
Arrays.sort(list,String.CASE_INSENSITIVE_ORDER);
for (String dirItem: list)
System.out.println(dirItem);
}
}
class DirFilter implements FilenameFilter{
private Pattern pattern;
public DirFilter(String regex){
pattern = Pattern.compile(regex);
}
@Override
public boolean accept(File dir, String name) {
return pattern.matcher(name).matches();
}
}
list方法 会将该目录下的每个文件调用accept,来判断该文件是否包含在内。
public String[] list(FilenameFilter filter) {
String names[] = list();
if ((names == null) || (filter == null)) {
return names;
}
List<String> v = new ArrayList<>();
for (int i = 0 ; i < names.length ; i++) {
if (filter.accept(this, names[i])) {
v.add(names[i]);
}
}
return v.toArray(new String[v.size()]);
}
匿名内部类改写
package io;
import java.io.File;
import java.io.FilenameFilter;
import java.util.Arrays;
import java.util.regex.Pattern;
// args: .*\.java
public class DirList2 {
public static FilenameFilter filter(String regex){ //编译器默认会给匿名内部类的外部变量
return new FilenameFilter() {
private Pattern pattern = Pattern.compile(regex);
@Override
public boolean accept(File dir, String name) {
return pattern.matcher(name).matches();
}
};
}
public static void main(String[] args) {
File path = new File("/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io");
String[] list;
if (args.length== 0)
list = path.list();//指定目录的全部列表
else
list = path.list(filter(args[0]));//指定目录的受限列表,使用FilenameFilter 筛选器
Arrays.sort(list,String.CASE_INSENSITIVE_ORDER);
for (String dirItem: list)
System.out.println(dirItem);
}
}
package io;
import java.io.File;
import java.io.FilenameFilter;
import java.util.Arrays;
import java.util.regex.Pattern;
// args: .*\.java
public class DirList3 {
public static void main(String[] args) {
File path = new File("/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io");
String[] list;
if (args.length== 0)
list = path.list();//指定目录的全部列表
else
list = path.list(new FilenameFilter() {
private Pattern pattern = Pattern.compile(args[0]);
@Override
public boolean accept(File dir, String name) {
return pattern.matcher(name).matches();
}
});//指定目录的受限列表,使用FilenameFilter 筛选器
Arrays.sort(list,String.CASE_INSENSITIVE_ORDER);
for (String dirItem: list)
System.out.println(dirItem);
}
}
优点:代码隔离,聚拢
缺点:不易阅读,谨慎使用
作业1
package io.e1;
import net.mindview.util.TextFile;
import java.io.File;
import java.io.FilenameFilter;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
// args: .*\.java
public class DirList3 {
public static void main(String[] args) {
// File path = new File(".");
File path = new File("/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io");
String[] list;
if (args.length == 0)
list = path.list();//指定目录的全部列表
else
list = path.list(new FilenameFilter() {
// 只分析指定后缀的文件,否则对于目录,需要额外处理
private String ext = args[0].toLowerCase();
@Override
public boolean accept(File dir, String name) {
if (name.toLowerCase().endsWith(ext)){
//只过滤指定文件类型
if (args.length == 1)
return true;
Set<String> words = new HashSet<>(new TextFile(new File(dir, name).getAbsolutePath(), "\\W+"));
for (int i = 1;i < args.length;i++)// 除第一个参数为后缀,尾随参数,是需要遍历检查,是否在文件中
if (words.contains(args[i]))
return true;
}
return false;
}
});//指定目录的受限列表,使用FilenameFilter 筛选器
Arrays.sort(list, String.CASE_INSENSITIVE_ORDER);
for (String dirItem : list)
System.out.println(dirItem);
}
}
package io.e2;
import java.io.File;
import java.io.FilenameFilter;
import java.util.Arrays;
import java.util.regex.Pattern;
public class SortedDirList {
private File path;
public SortedDirList() {
path = new File(".");
}
public SortedDirList(File path) {
this.path = path;
}
String[] list() {
String[] list = path.list();
Arrays.sort(list, String.CASE_INSENSITIVE_ORDER);
return list;
}
String[] list(String regex) {
String[] list = path.list(new FilenameFilter() {
private Pattern pattern = Pattern.compile(regex);
@Override
public boolean accept(File dir, String name) {
return pattern.matcher(name).matches();
}
});
Arrays.sort(list, String.CASE_INSENSITIVE_ORDER);
return list;
}
public static void main(String[] args) {
SortedDirList dir = new SortedDirList();
System.out.println((Arrays.asList(dir.list(".*\\.java"))));
}
}
package io.e3;
import java.io.File;
import java.io.FilenameFilter;
import java.util.Arrays;
import java.util.regex.Pattern;
// args: .*\.java
public class DirList3 {
public static void main(String[] args) {
File path = new File("/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io");
String[] list;
if (args.length == 0)
list = path.list();//指定目录的全部列表
else
list = path.list(new FilenameFilter() {
private Pattern pattern = Pattern.compile(args[0]);
@Override
public boolean accept(File dir, String name) {
return pattern.matcher(name).matches();
}
});//指定目录的受限列表,使用FilenameFilter 筛选器
long total = 0;
long fs;
for (String dirItem : list) {
fs = new File(path, dirItem).length();
System.out.println(dirItem + ", " + fs + " bytes");
total += fs;
}
System.out.println("=========");
System.out.println(list.length + "files(s)," + total + " bytes");
}
}
1.2 目录实用工具
package io;
import net.mindview.util.PPrint;
import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;
public final class Directory {
public static File[]
local(File dir,final String regex){
return dir.listFiles(new FilenameFilter() {
private Pattern pattern = Pattern.compile(regex);
@Override
public boolean accept(File dir, String name) {
return pattern.matcher(new File(name).getName()).matches();
}
});
}
// Overloaded
public static File[]
local(String path,final String regex){
return local(new File(path),regex);
}
public static class TreeInfo implements Iterable<File> { //实际是对象 "元组",普通文件和目录的集合
public List<File> files = new ArrayList<>();
public List<File> dirs = new ArrayList<>();
@Override
public Iterator<File> iterator() {
return files.iterator(); //默认迭代是file
}
void addAll(TreeInfo other) {
files.addAll(other.files);
files.addAll(other.dirs);
}
public String toString() {
return "dirs: " + PPrint.pformat(dirs) +
"\n\nfiles:: " + PPrint.pformat(files);
}
}
public static TreeInfo walk(String start,String regex){
return reCurseDirs(new File(start),regex);
}
public static TreeInfo walk(File start){
return reCurseDirs(start,".*");
}
public static TreeInfo walk(String start) {
return reCurseDirs(new File(start),".*");
}
static TreeInfo reCurseDirs(File startDir,String regex){
TreeInfo result = new TreeInfo();
for (File item: startDir.listFiles()){
if (item.isDirectory()){//目录
result.dirs.add(item);
result.addAll(reCurseDirs(item,regex));//递归目录
}else // 文件
if (item.getName().matches(regex))
result.files.add(item);
}
return result;
}
public static void main(String[] args) {
if (args.length == 0)
System.out.println(walk("."));
else
for (String arg:args)
System.out.println(walk(arg));
}
}
策略模式,处理目录中的文件
package io;
import java.io.File;
import java.io.IOException;
public class ProcessFiles {
public interface Strategy {
void process(File file);
}
private Strategy strategy;
private String ext;
public ProcessFiles(Strategy strategy, String ext) {
this.strategy = strategy;
this.ext = ext;
}
public void start(String[] args) {
try {
if (args.length == 0)
processDirectoryTree(new File("."));
else for (String arg : args) {// 指定一个或多个目录,或指定特定文件
File fileArg = new File(arg);
if (fileArg.isDirectory()) // 目录
processDirectoryTree(fileArg);
else {// 文件
// Allow user to leave off extension:
if (!arg.endsWith("." + ext)) //文件没有扩展名,给加上
arg += "." + ext;
strategy.process(new File(arg).getCanonicalFile());
}
}
}catch (IOException e){
throw new RuntimeException(e);
}
}
public void processDirectoryTree(File root) throws IOException {
for (File file: Directory.walk(root.getAbsolutePath(),".*\\." + ext))
strategy.process(file.getCanonicalFile());
}
public static void main(String[] args) {
new ProcessFiles(new Strategy() {
@Override
public void process(File file) {
System.out.println(file);
}
}, "java").start(args);
}
}
作业4
package io.e4;
import io.Directory;
import java.io.File;
// args: .*\.java
public class E4 {
public static void main(String[] args) {
Directory.TreeInfo ti;
String start = new File(".").getAbsolutePath()+"/src/main/java/io";
if (args.length == 0)
ti = Directory.walk(start);
else
ti = Directory.walk(start,args[0]);
long total = 0;
for (File file: ti)
total += file.length();
System.out.println( ti.files.size() + " file(s), " + total + "bytes");
}
}
1.3目录的检查及创建
package io;
import java.io.File;
// {Args: MakeDirectoriesTest}
public class MakeDirectories {
private static void usage() {
System.err.println(
"Usage:MakeDirectories path1 ... \n" +
"Creates each path\n" +
"Usage:MakeDirectories -d path1 ...\n" +
"Deletes each path\n" +
"Usage:MakeDirectories -r path1 path2\n" +
"Renames from path1 to path2");
System.exit(1);
}
private static void fileData(File f) {
System.out.println(
"Absolute path: " + f.getAbsolutePath() +
"\n Can read: " + f.canRead() +
"\n Can write: " + f.canWrite() +
"\n getName: " + f.getName() +
"\n getParent: " + f.getParent() + //路径名是MakeDirectoriesTest,从这个路径字符串解析不出来上级路经 所以是null
"\n getPath: " + f.getPath() +
"\n length: " + f.length() +
"\n lastModified: " + f.lastModified());
if (f.isFile())
System.out.println("It's a file");
else if (f.isDirectory())
System.out.println("It's a directory.");
}
public static void main(String[] args) {
if (args.length < 1) usage();
if (args[0].equals("-r")) { // rename
if (args.length != 3) usage(); // 需要三个参数,若参数数量不正确,告知usage,退出
File
old = new File(args[1]),// 源文件
rname = new File(args[2]);// 重命名文件
old.renameTo(rname);//重命名
fileData(old);//被删除的文件信息
fileData(rname);//新文件信息
return;//Exit main
}
int count = 0;
boolean del = false;
if (args[0].equals("-d")) {//删除标记
count++;
del = true;
}
count--; //将删除 和 创建dir 统一处理
while (++count < args.length) {
File f = new File(args[count]);
if (f.exists()) {
System.out.println(f + " exists");
if (del) {
System.out.println("deleting..." + f);
f.delete();
}
} else {// 不存在
if (!del) {//不是删除,也就是 mkdir
f.mkdirs();
System.out.println("created " + f);
}
}
fileData(f);
}
}
}
/*
args: -d /Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test1 /Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test2
/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test1 exists
deleting.../Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test1
Absolute path: /Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test1
Can read: false
Can write: false
getName: test1
getParent: /Users/erin/JavaProject/thinking_in_java_example/src/main/java/io
getPath: /Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test1
length: 0
lastModified: 0
/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test2 exists
deleting.../Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test2
Absolute path: /Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test2
Can read: false
Can write: false
getName: test2
getParent: /Users/erin/JavaProject/thinking_in_java_example/src/main/java/io
getPath: /Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test2
length: 0
lastModified: 0
args: -r /Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test /Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test1
Absolute path: /Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test
Can read: false
Can write: false
getName: test
getParent: /Users/erin/JavaProject/thinking_in_java_example/src/main/java/io
getPath: /Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test
length: 0
lastModified: 0
Absolute path: /Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test1
Can read: true
Can write: true
getName: test1
getParent: /Users/erin/JavaProject/thinking_in_java_example/src/main/java/io
getPath: /Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test1
length: 26
lastModified: 1576557859000
It's a file
args: -d MakeDirectoriesTest
MakeDirectoriesTest exists
deleting...MakeDirectoriesTest
Absolute path: /Users/erin/JavaProject/thinking_in_java_example/MakeDirectoriesTest
Can read: false
Can write: false
getName: MakeDirectoriesTest
getParent: null
getPath: MakeDirectoriesTest
length: 0
lastModified: 0
Disconnected from the target VM, address: '127.0.0.1:60489', transport: 'socket'
args: MakeDirectoriesTest
Connected to the target VM, address: '127.0.0.1:60500', transport: 'socket'
created MakeDirectoriesTest
Absolute path: /Users/erin/JavaProject/thinking_in_java_example/MakeDirectoriesTest
Can read: true
Can write: true
getName: MakeDirectoriesTest
getParent: null
getPath: MakeDirectoriesTest
length: 64
lastModified: 1576562665000
It's a directory.
再次运行
*/
2 输入和输出
Java中“流”类库让人迷惑的主要原因就在于:创建单一的结果流,却需要创建多个对象。
2.1 InputStream类型
6 典型的I/O流使用方式
6.1 缓冲输入文件
package io;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class BufferedInputFile {
public static String read(String filename) throws IOException {
// 逐行读入
// public class FileReader extends InputStreamReader
// public class InputStreamReader extends Reader
BufferedReader in =new BufferedReader(new FileReader(filename));//提高速度,对文件进行缓冲
String s;
StringBuilder sb = new StringBuilder();
while ((s = in.readLine())!=null)
sb.append(s + "\n");// readline 已经将\n删掉,故需要 添加换行符
in.close(); // 显式调用close
return sb.toString();
}
public static void main(String[] args) throws IOException {
System.out.println(read("/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/BufferedInputFile.java"));
}
}
6.2从内存输入
从内存读入字符串
package io;
import java.io.IOException;
import java.io.StringReader;
// public class StringReader extends Reader
// public StringReader(String s)
public class MemoryInput {
public static void main(String[] args) throws IOException {
StringReader in = new StringReader(BufferedInputFile.read("/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/MemoryInput.java"));
int c;
while ((c = in.read()) != -1)
System.out.print((char)c);
}
}
6.3 格式化的内存输入
package io;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
public class FormattedMemoryInput {
public static void main(String[] args) {
try {
DataInputStream in = new DataInputStream(
new ByteArrayInputStream(
BufferedInputFile.read(
"/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/FormattedMemoryInput.java").getBytes()));
while (true)
System.out.print((char)in.readByte());
} catch (IOException e){
System.err.println("End of stream");
}
}
}
package io;
import java.io.*;
public class TestEOF {
public static void main(String[] args) throws IOException {
DataInputStream in = new DataInputStream(
new BufferedInputStream(
new FileInputStream("/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/TestEOF.java")));
while (in.available() != 0)
System.out.print((char)in.readByte());
}
}
6.4 基本的文件输出
PrintWriter
package io;
import java.io.*;
public class BasicFileOutput {
static String fileJava = "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/BasicFileOutput.java";//读入文件
static String fileOutput = "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/BasicFileOutput.out";//输出文件
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(
new StringReader(
BufferedInputFile.read(fileJava)
)
);
PrintWriter out = new PrintWriter(
new BufferedWriter(new FileWriter(fileOutput))
);
int lineCount = 1;
String s;
while ((s = in.readLine())!= null)
out.println(lineCount++ + ": " + s);
out.close();//显式调用close,若不close,缓冲区内容不会刷新清空。它们就不完整。
in.close(); // 关闭 源文件
System.out.println(BufferedInputFile.read(fileOutput));
}
}
/*
LineNumberReader 是个 silly class 没有用。
记录行号很容易。
*/
文本文件输出的快捷方式
同上,但其他常见的写入任务 没有快捷方式
package io;
import chapter6access.Print;
import java.io.*;
public class FileOutputShortcut {
static String base = "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/";
static String file = base + "FileOutputShortcut.out";
static String fileJava = base + "FileOutputShortcut.java";
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(
new StringReader(
BufferedInputFile.read(fileJava)));
// shortcut
PrintWriter out = new PrintWriter(file);
/*
public PrintWriter(String fileName) throws FileNotFoundException {
this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName))),
false);
}
*/
int lineCount = 1;
String s;
while ((s = in.readLine()) != null)
out.println(lineCount++ + ": " + s);
out.close();
System.out.println(BufferedInputFile.read(file));
in.close();
}
}
写入文件,有无IO的比较
package io.e14;
import io.e7.E7;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
public class E14_BufferPerformance {
static String base = "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/e14/";
static String fileOutput = base + "E14_BufferPerformance.out";
static String fileJava = base + "E14_BufferPerformance.java";
public static void main(String[] args)
throws IOException {
List<String> list = E7.read(fileJava);
PrintWriter out = new PrintWriter(
new BufferedWriter(new FileWriter(fileOutput)));
int lineCount = 1;
long t1 = System.currentTimeMillis();
for(String s : list) {
for(int i = 0; i < 10000; i++)
out.println(lineCount + ": " + s);
lineCount++;
}
long t2 = System.currentTimeMillis();
System.out.println("buffered: " + (t2 - t1));
out.close();
out = new PrintWriter(new FileWriter(fileOutput));
lineCount = 1;
t1 = System.currentTimeMillis();
for(String s : list) {
for(int i = 0; i < 10000; i++)
out.println(lineCount + ": " + s);
lineCount++;
}
t2 = System.currentTimeMillis();
System.out.println("unbuffered: " + (t2 - t1));
out.close();
}
}
/*
buffered: 104
unbuffered: 227
*/
6.5 存储和恢复数据
package io;
import java.io.*;
public class StoringAndRecoveringData {
static String base = "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/";
static String file = base + "test0";
public static void main(String[] args) throws IOException {
DataOutputStream out = new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream(file))); //创建文件
out.writeDouble(3.14159);
out.writeUTF("That was pi");
out.writeDouble(1.41413);
out.writeUTF("Square root of 2");
out.close();
DataInputStream in = new DataInputStream(
new BufferedInputStream(
new FileInputStream(file)));
System.out.println(in.readDouble());//按存的顺序读取
System.out.println(in.readUTF());
System.out.println(in.readDouble());
System.out.println(in.readUTF());
}
}
/*
DataInputStream DataOutputStream 面向字节流,使用OutputStream InputStream
这种方式不常用。
3.14159
That was pi
1.41413
Square root of 2
*/
http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html
UTF-8 的编码规则很简单,只有二条:
1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。
2)对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。
UTF-8 的编码
Unicode符号范围 | UTF-8编码方式
(十六进制) | (二进制)
----------------------+---------------------------------------------
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
static int writeUTF(String str, DataOutput out) throws IOException {
int strlen = str.length();
int utflen = 0;
int c, count = 0;
/* use charAt instead of copying String to char array */
for (int i = 0; i < strlen; i++) {
c = str.charAt(i);
if ((c >= 0x0001) && (c <= 0x007F)) {
utflen++;
} else if (c > 0x07FF) {
utflen += 3;
} else {
utflen += 2;
}
}
if (utflen > 65535)
throw new UTFDataFormatException(
"encoded string too long: " + utflen + " bytes");
byte[] bytearr = null;
if (out instanceof DataOutputStream) {
DataOutputStream dos = (DataOutputStream)out;
if(dos.bytearr == null || (dos.bytearr.length < (utflen+2)))
dos.bytearr = new byte[(utflen*2) + 2];
bytearr = dos.bytearr;
} else {
bytearr = new byte[utflen+2];
}
// 字节数组 的前两个字节,保存UTF-8的长度
bytearr[count++] = (byte) ((utflen >>> 8) & 0xFF);
bytearr[count++] = (byte) ((utflen >>> 0) & 0xFF);
// 单字节预处理
int i=0;
for (i=0; i<strlen; i++) {
c = str.charAt(i);
if (!((c >= 0x0001) && (c <= 0x007F))) break;
bytearr[count++] = (byte) c;
}
// 预处理后,数据处理
for (;i < strlen; i++){
c = str.charAt(i);
if ((c >= 0x0001) && (c <= 0x007F)) {
bytearr[count++] = (byte) c;
} else if (c > 0x07FF) {
bytearr[count++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
bytearr[count++] = (byte) (0x80 | ((c >> 6) & 0x3F));
bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F));
} else {
bytearr[count++] = (byte) (0xC0 | ((c >> 6) & 0x1F));
bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F));
}
}
out.write(bytearr, 0, utflen+2);
return utflen + 2;
}
6.6 读写随机访问文件
6.7 管道流
21章 多线程
7 文件读写的使用工具
8 标准I/O
8.1 从标准输入中读取
System.in public final static InputStream in = null;
System.out public final static PrintStream out = null;
System.err public final static PrintStream err = null;
package io;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Echo {// 回显输入的每一行
public static void main(String[] args) throws IOException {
BufferedReader stdin = new BufferedReader(
new InputStreamReader(System.in));
String s;
while ((s = stdin.readLine()) != null && s.length() != 0)
System.out.println(s);
}
}
8.2 将System.out 转换成 PrinterWriter
package io;
import java.io.PrintWriter;
public class ChangeSystemOut {
public static void main(String[] args) {
PrintWriter out = new PrintWriter(System.out,true);//打印流是输出流的子类,true 自动清空功能
out.println("hello,world");
}
}
8.标准I/O重定向
import java.io.*;
public class Redirecting {
static String filePath = "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/Redirecting.java";
public static void main(String[] args) throws IOException { // io 操纵字节流
PrintStream console = System.out;
BufferedInputStream in = new BufferedInputStream(new FileInputStream(filePath));
PrintStream out = new PrintStream(new BufferedOutputStream(new FileOutputStream("/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test.out")));
System.setIn(in); // 重定向
System.setOut(out);// 重定向
System.setErr(out);// 重定向
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String s;
while ((s = br.readLine())!= null)
System.out.println(s);
out.close();// 输出流关闭
System.setOut(console);// 改回来
}
}
9 进程控制
package io;
public class OSExcuteException extends RuntimeException{ // 继承运行时异常
public OSExcuteException(String why){
super(why);
}
}
package io;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class OsExecute {
public static void command(String command){
boolean err = false; // 命令执行 过程中,是否有错
try {
Process process = new ProcessBuilder(command.split(" .")).start();
BufferedReader results = new BufferedReader(
new InputStreamReader(process.getInputStream()));// 子进程的输入流,包装带缓冲的读取器
String s;
while ((s = results.readLine()) != null) // 读到输入流的内容
System.out.println(s);
BufferedReader errors = new BufferedReader(// 错误流
new InputStreamReader(process.getErrorStream()));
while ((s = errors.readLine()) != null) {
System.err.println(s);
err = true;
}
} catch (Exception e) {
if(! command.startsWith("CMD /c "))
command("CMD /C " + command);
else
throw new RuntimeException(e);
}
if (err)
throw new OSExcuteException("Errors executing " + command); // 抛出自定义异常
}
}
package io;
public class OsExecuteDemo {
public static void main(String[] args) {
OsExecute.command("ls");
// OsExecute.command("javap /Users/erin/JavaProject/thinking_in_java_example/src/main/java/jvm/OsExecuteDemo");
}
}
10 新 I/O
NIO主要有三大核心部分:Channel(通道),Buffer(缓冲区), Selector。
传统IO 基于字节流和字符流进行操作,
NIO 基于Channel和Buffer(缓冲区)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。
演示三种类型的流,用以产生可写,可读可写,可读的通道
package io;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class GetChannel {
private static final int BSIZE = 1024; // 1K
static String filePath = "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/data.txt";
public static void main(String[] args) throws IOException {
// 写文件
FileChannel fc = new FileOutputStream(filePath).getChannel();
fc.write(ByteBuffer.wrap("Some text ".getBytes()));
fc.close();
// 追加文件
fc = new RandomAccessFile(filePath,"rw").getChannel();
fc.position(fc.size());//移动FileChannel
fc.write(ByteBuffer.wrap("Some more".getBytes()));
fc.close();
// 只 读文件
fc = new FileInputStream(filePath).getChannel();
ByteBuffer buff = ByteBuffer.allocate(BSIZE);
fc.read(buff);
buff.flip();
while (buff.hasRemaining())
System.out.print((char) buff.get());
}
}
简单的文件复制
package io;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
// {Args:/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/ChannelCopy.java /Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test.txt }
public class ChannelCopy {
private static final int BSIZE = 1024;
public static void main(String[] args) throws IOException {
if (args.length != 2){
System.out.println("Arguments: sourcefile destfile");
System.exit(1);
}
FileChannel
in = new FileInputStream(args[0]).getChannel(),
out = new FileOutputStream(args[1]).getChannel();
ByteBuffer buffer = ByteBuffer.allocate(BSIZE);
while (in.read(buffer) != -1){
buffer.flip(); // 准备读
out.write(buffer);
buffer.clear();//准备写
}
}
}
上述不是处理此类操作的理想方式。transferTo transferFrom将一个通道和另一个通道相连
package io;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
public class TransferTo {
static String srcPath = "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/TransferTo.java";
static String desPath = "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/TransferTo.txt";
public static void main(String[] args) throws IOException {
FileChannel
in = new FileInputStream(srcPath).getChannel(),
out = new FileOutputStream(desPath).getChannel();
in.transferTo(0,in.size(),out);
// out.transferFrom(in,0,in.size());
}
}
10.1 转换数据
GetChannel 是字节缓冲器
10.2 获取基本类型
10.3 视图缓冲器
10.4 用缓冲器操纵数据
10.5 缓冲器细节
10.6 内存映射文件
10.7 文件加锁
11 压缩
属于InputStream OutputStream继承层次结构,压缩类库,按字节方式,而不是字符方式处理。
ZIP 和GZIP最常用
11.1 用GZIP进行简单压缩
单数据流进行压缩
package io;
import java.io.*;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
//{Args:/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/GZIPcompress.java}
public class GZIPcompress {
static String gzFile = "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test.gz";
public static void main(String[] args) throws IOException {
if (args.length == 0){
System.out.println(
"Usage: \nGZIPcompress file\n" +
"\tUses GZIP compression to compress " +
"the file to test.gz");
System.exit(1);
}
// 1. 被压缩的文件
BufferedReader in = new BufferedReader(
new FileReader(args[0]));
// 2. 生成压缩文件 将输出流 封装成 GZIPOutputStream
BufferedOutputStream out = new BufferedOutputStream(
new GZIPOutputStream(
new FileOutputStream(gzFile)));
// 写入压缩文件
System.out.println("Writing file");
int c;
while ((c = in.read())!= -1)
out.write(c);
in.close();
out.close();
// 读取压缩文件 将输入流 封装成 GZIPOutputStream
System.out.println("Reading file");
BufferedReader in2 = new BufferedReader(
new InputStreamReader(new GZIPInputStream(
new FileInputStream(gzFile))));
String s;
while ((s = in2.readLine())!= null)
System.out.println(s);
}
}
11.2 用Zip进行多文件保存
Checksum 类 用来计算和校验文件的校验和的方法。有两种Checksum类型:Adler32(更快些)和 CRC32(慢一些,但更准确)
package io;
import java.io.*;
import java.util.Enumeration;
import java.util.zip.*;
public class ZipCompress {
static String zipFile= "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test.zip";
public static void main(String[] args) throws IOException {
FileOutputStream f = new FileOutputStream(zipFile);
// public class CheckedOutputStream extends FilterOutputStream 校验和 用于验证输出数据的完整性
CheckedOutputStream csum = new CheckedOutputStream(f,new Adler32());
ZipOutputStream zos = new ZipOutputStream(csum);
BufferedOutputStream out = new BufferedOutputStream(zos);
zos.setComment("A test of Java Zipping"); // 设置ZIP 文件注释
for (String arg: args){
System.out.println("Writing file " + arg);
BufferedReader in = new BufferedReader(new FileReader(arg));
//开始写入新的 ZIP 文件条目并将流定位到条目数据的开始处
//ZipEntry是Java中进行压缩与解压缩的单位,它用来标记ZIP压缩文件中每个原始文件的入口
zos.putNextEntry(new ZipEntry(arg));
int c;
while ((c = in.read()) != -1)
out.write(c);
in.close();
out.flush();
}
out.close();
System.out.println("Checksum: " + csum.getChecksum().getValue());
// 解压缩
System.out.println("Reading file");
FileInputStream fi = new FileInputStream(zipFile);
CheckedInputStream csumi = new CheckedInputStream(fi,new Adler32());
ZipInputStream in2 = new ZipInputStream(csumi);
BufferedInputStream bis = new BufferedInputStream(in2);
ZipEntry ze;
while ((ze = in2.getNextEntry()) != null){
System.out.println("Reading file " + ze);
int x;
while ((x = bis.read()) != -1)
System.out.write(x); //输出字符流
}
if (args.length == 1)
System.out.println("Checksum: " + csumi.getChecksum().getValue());
bis.close();
// 另种方式 打开和读取zip文件 查看压缩文件的目录
ZipFile zf = new ZipFile(zipFile);
Enumeration e = zf.entries();
while (e.hasMoreElements()){
ZipEntry ze2 = (ZipEntry)e.nextElement();
System.out.println("File: " + ze2);
//...and extract the data as before
}
// if args.length == 1
}
}
11.3 Java档案文件
Zip格式应用于JAR(Java ARchive)文件格式中,JAR跨平台
JAR文件 一组压缩文件构成,且有一张“文件清单”(自行创建或jar程序自动生成)
Sun JDK自带jar程序 jar [options] destination [manifest] inputfile(s)
jar cf myJarFile.jar *.class
jar cmf myJarFile.jar myManifestFile.mf *.class 自建清单文件
jar tf myJarFile.jar 产生所有文件的一个目录表
jar tvf myJarFile.jar 详尽
jar cvf myApp.jar audio classes image 将子目录合并到文件myAppljar中
0选项创建JAR文件,文件可放入类路径变量(CLASSPATH)中
12 对象序列化
package io;
import java.io.*;
import java.util.Random;
class Data implements Serializable{
private int n;
public Data(int n){this.n = n;}
public String toString(){return Integer.toString(n);}
}
public class Worm implements Serializable{
private static Random rand = new Random(47);
private Data[] d ={ // 数据成员也是可序列化
new Data(rand.nextInt(10)),
new Data(rand.nextInt(10)),
new Data(rand.nextInt(10))
};
private Worm next;
private char c;
public Worm(int i,char x){
System.out.println("Worm constructor: " + i);
c = x;
if (--i > 0)
next = new Worm(i,(char)(x + 1));
}
public Worm(){
System.out.println("Default constructor");
}
public String toString(){
StringBuilder result = new StringBuilder(":");
result.append(c);
result.append("(");
for (Data dat:d)
result.append(dat);
result.append(")");
if (next != null)
result.append(next);
return result.toString();
}
// 可序列化到文件或数据库
static String wormOut = "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/Worm.out";
public static void main(String[] args) throws IOException, ClassNotFoundException {
//
Worm w = new Worm(6,'a');
System.out.println("w = " + w);
//读写文件
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(wormOut));
out.writeObject("Worm storage\n");
out.writeObject(w);
out.close();
ObjectInputStream in = new ObjectInputStream(new FileInputStream(wormOut));
String s = (String)in.readObject();
Worm w2 = (Worm)in.readObject();
System.out.println(s + "w2 = " + w2);
//读写字节数组
ByteArrayOutputStream bout = new ByteArrayOutputStream();
ObjectOutputStream out2 = new ObjectOutputStream(bout);
out2.writeObject("Worm storage\n");
out2.writeObject(w);
out2.flush();
ObjectInputStream in2 = new ObjectInputStream(new ByteArrayInputStream(bout.toByteArray()));
s = (String)in2.readObject();
Worm w3 = (Worm)in2.readObject();
System.out.println(s + "w3 = " + w3);
}
}
12.1 寻找类
package io;
import java.io.*;
public class Alien implements Serializable {
}
package io;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class FreezeAlien {
static String outFile = "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/X.file";
public static void main(String[] args) throws IOException {
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(outFile));
Alien auellek = new Alien();
out.writeObject(auellek);
}
}
保证java虚拟机能找到.class文件
package io.Xfiles;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class ThawAlien {//解冻外星人
static String outFile = "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/X.file";
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectInputStream in = new ObjectInputStream(new FileInputStream(outFile));
Object mystery = in.readObject();
System.out.println(mystery.getClass()); //删掉 class后,ClassNotFoundException
}
}
/*
class io.Alien
*/
12.2 序列化的控制
Externalizable 对序列化过程进行控制
自动调用
public void writeExternal(ObjectOutput out) throws IOException { //序列化
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {//反序列化
Serializable 以存储的二进制为基础来构造,不需要调用构造器
Externalizable 普通的默认构造器都会被调用
package io;
import java.io.*;
class Blips1 implements Externalizable {
public Blips1(){
System.out.println("Blips1 Constructor");
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
System.out.println("Blips1.writeExternal");
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
System.out.println("Blips1.readExternal");
}
}
class Blips2 implements Externalizable {
Blips2(){
System.out.println("Blips2 Constructor");
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
System.out.println("Blips2.writeExternal");
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
System.out.println("Blips2.readExternal");
}
}
public class Blips{
static String outFile = "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/Blips.out";
public static void main(String[] args) throws IOException, ClassNotFoundException {
System.out.println("Constructing objects:");
Blips1 b1 = new Blips1();
Blips2 b2 = new Blips2();
ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream(outFile));
System.out.println("Saving objects:");
o.writeObject(b1);
o.writeObject(b2);
o.close();
ObjectInputStream in = new ObjectInputStream(new FileInputStream(outFile));
System.out.println("Recovering b1:");
b1 = (Blips1) in.readObject();
System.out.println("Recovering b2:");
b2 = (Blips2) in.readObject(); //调用默认构造器,但不是public InvalidClassException
}
}
/*
Constructing objects:
Blips1 Constructor
Blips2 Constructor
Saving objects:
Blips1.writeExternal
Blips2.writeExternal
Recovering b1:
Blips1 Constructor
Blips1.readExternal
Recovering b2:
*/
对象的某一部分被序列化 Externalizable writeExternal/readExternal
package io;
import java.io.*;
public class Blip3 implements Externalizable {
// 未初始化
private int i;
private String s;
public Blip3(){//默认构造器
System.out.println("Blip3 Constructor");
}
public Blip3(String x, int a){//非默认构造器
System.out.println("Blip3(String s, int i)");
s = x;
i = a;
}
public String toString(){return s + i; }
@Override
public void writeExternal(ObjectOutput out) throws IOException { // 把希望序列化的部分存起来
System.out.println("Blip3.writeExternal");
// you must do this
out.writeObject(s);
out.writeInt(i);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
System.out.println("Blip3.readExternal");
// you must do this
s =(String)in.readObject();
i = in.readInt();
}
static String outFile= "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/Blip3.out";
public static void main(String[] args) throws IOException, ClassNotFoundException {
System.out.println("Construction objects:");
Blip3 b3 = new Blip3("A String ", 47);
System.out.println(b3);
ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream(outFile));
System.out.println("Saving object:");
o.writeObject(b3);
o.close();
ObjectInputStream in = new ObjectInputStream(new FileInputStream(outFile));
System.out.println("Recoving b3: ");
b3 = (Blip3)in.readObject();
System.out.println(b3);
}
}
transient(瞬时)关键字
Externalizable 没有任何东西可以自动序列化,可以在writeExternal内部对所需部分进行显示的序列化
Serializable 序列化自动进行。可以用transient 逐个字段关闭序列化
package io;
import java.io.*;
import java.util.Date;
import java.util.concurrent.TimeUnit;
public class Logon implements Serializable {
private Date date = new Date();
private String username;
private transient String password;
public Logon(String name, String pwd) {
username = name;
password = pwd;
}
public String toString() {
return "Logon info: \n username: " + username + "\n date: " + date + "\n password: " + password;
}
static String outFile = "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/Logon.out";
public static void main(String[] args) throws IOException, InterruptedException, ClassNotFoundException {
Logon a = new Logon("Hulk", "myLittlePony");
System.out.println("Logon a = " + a);
ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream(outFile));
o.writeObject(a);
o.close();
TimeUnit.SECONDS.sleep(1);
ObjectInputStream in = new ObjectInputStream(new FileInputStream(outFile));
System.out.println("Recoving object at " + new Date());
a = (Logon) in.readObject();
System.out.println("logon a = " + a);
}
}
/*
Logon a = Logon info:
username: Hulk
date: Fri Dec 27 14:40:14 CST 2019
password: myLittlePony
Recoving object at Fri Dec 27 14:40:15 CST 2019
logon a = Logon info:
username: Hulk
date: Fri Dec 27 14:40:14 CST 2019
password: null
*/
12.3 使用“持久性”
两个对象都有指向第三个对象的引用,进行序列化
package io;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
class House implements Serializable {
}
class Animal implements Serializable {
private String name;
private House preferredHouse;
Animal(String nm, House h) {
name = nm;
preferredHouse = h;
}
public String toString() {
return name + "[" + super.toString() + "]," + preferredHouse + "\n";
}
}
public class MyWorld {
public static void main(String[] args) throws IOException, ClassNotFoundException {
House house = new House();
List<Animal> animals = new ArrayList<>();
animals.add(new Animal("Bosco the dog", house));
animals.add(new Animal("Ralph the hamster", house));
animals.add(new Animal("Molly the cat", house));
System.out.println("animals: " + animals);
ByteArrayOutputStream buf1 = new ByteArrayOutputStream(); // 字节数组, 对Serializable对象对“deep copy”
ObjectOutputStream o1 = new ObjectOutputStream(buf1);
o1.writeObject(animals);
o1.writeObject(animals);
ByteArrayOutputStream buf2 = new ByteArrayOutputStream();
ObjectOutputStream o2 = new ObjectOutputStream(buf2);
o2.writeObject(animals);
ObjectInputStream in1 = new ObjectInputStream(new ByteArrayInputStream(buf1.toByteArray()));
ObjectInputStream in2 = new ObjectInputStream(new ByteArrayInputStream(buf2.toByteArray()));
List
animals1 = (List) in1.readObject(),
animals2 = (List) in1.readObject(),
animals3 = (List) in2.readObject();
System.out.println("animals1: " + animals1);
System.out.println("animals2: " + animals2);
System.out.println("animals3: " + animals3);
}
}
/*
animals: [Bosco the dog[io.Animal@5e481248],io.House@66d3c617
, Ralph the hamster[io.Animal@63947c6b],io.House@66d3c617
, Molly the cat[io.Animal@2b193f2d],io.House@66d3c617
]
animals1: [Bosco the dog[io.Animal@1b2c6ec2],io.House@4edde6e5
, Ralph the hamster[io.Animal@70177ecd],io.House@4edde6e5
, Molly the cat[io.Animal@1e80bfe8],io.House@4edde6e5
]
animals2: [Bosco the dog[io.Animal@1b2c6ec2],io.House@4edde6e5
, Ralph the hamster[io.Animal@70177ecd],io.House@4edde6e5
, Molly the cat[io.Animal@1e80bfe8],io.House@4edde6e5
]
animals3: [Bosco the dog[io.Animal@66a29884],io.House@4769b07b //系统无法知道流内的对象是第一个流的对象的别名,因此会产生除完全不同的对象网
, Ralph the hamster[io.Animal@cc34f4d],io.House@4769b07b
, Molly the cat[io.Animal@17a7cec2],io.House@4769b07b
]
*/
保存系统状态,最安全对做法是 将其作为“原子”操作进行序列化
package io;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
abstract class Shape implements Serializable{
public static final int RED = 1,BLUE = 2,GREEN=3;
private int xPos,yPos,dimension;
private static Random rand = new Random();
private static int counter = 0;
public abstract void setColor(int newColor);
public abstract int getColor();
public Shape(int xVal,int yVal,int dim){
xPos = xVal;
yPos = yVal;
dimension = dim;
}
public String toString(){
return getClass() + "color[" + getColor() + "] xPos[" + xPos + "] yPos[" + yPos + "] dim[" +dimension + "]\n";
}
public static Shape randomFactory(){
int xVal = rand.nextInt(100);
int yVal = rand.nextInt(100);
int dim = rand.nextInt(100);
switch (counter++ % 3){
default:
case 0: return new Circle(xVal,yVal,dim);
case 1: return new Square(xVal,yVal,dim);
case 2: return new Line(xVal,yVal,dim);
}
}
}
class Circle extends Shape{
private static int color = RED; // 静态成员变量有初值
public Circle(int xVal, int yVal, int dim) {
super(xVal, yVal, dim);
}
@Override
public void setColor(int newColor) { color = newColor;}
@Override
public int getColor() { return color;}
}
class Square extends Shape{
private static int color;// 静态成员变量无初值
public Square(int xVal, int yVal, int dim) {
super(xVal, yVal, dim);
color = RED; // 构造函数内 设置静态成员变量值
}
@Override
public void setColor(int newColor) { color = newColor;}
@Override
public int getColor() { return color;}
}
class Line extends Shape{
private static int color = RED; // 静态成员变量有初值
public static void serializeStaticState(ObjectOutputStream os) throws IOException {
os.writeInt(color);
}
public static void derializeStaticState(ObjectInputStream is) throws IOException {
color = is.readInt();
}
public Line(int xVal, int yVal, int dim) {
super(xVal, yVal, dim);
}
@Override
public void setColor(int newColor) { color = newColor;}
@Override
public int getColor() { return color;}
}
public class StoreCADState {
static String outFile = "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/StoreCADState.out";
public static void main(String[] args) throws IOException {
List<Class<? extends Shape>> shapeTypes = new ArrayList<>();
shapeTypes.add(Circle.class);
shapeTypes.add(Square.class);
shapeTypes.add(Line.class);
List<Shape> shapes = new ArrayList<>();
for (int i = 0; i < 10; i++)
shapes.add(Shape.randomFactory());
// 设置全部 颜色 为绿色
for (int i = 0; i < 10; i++)
shapes.get(i).setColor(Shape.GREEN);
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(outFile));
out.writeObject(shapeTypes); // 保存class对象
Line.serializeStaticState(out);
out.writeObject(shapes);// 保存几何形状
System.out.println(shapes);
}
}
/*
[class io.Circlecolor[3] xPos[70] yPos[7] dim[19]
, class io.Squarecolor[3] xPos[86] yPos[65] dim[56]
, class io.Linecolor[3] xPos[36] yPos[56] dim[20]
, class io.Circlecolor[3] xPos[94] yPos[35] dim[0]
, class io.Squarecolor[3] xPos[41] yPos[99] dim[88]
, class io.Linecolor[3] xPos[64] yPos[69] dim[79]
, class io.Circlecolor[3] xPos[53] yPos[21] dim[19]
, class io.Squarecolor[3] xPos[28] yPos[86] dim[75]
, class io.Linecolor[3] xPos[90] yPos[85] dim[16]
, class io.Circlecolor[3] xPos[20] yPos[65] dim[63]
]
*/
package io;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.List;
public class RecoverCADState {
static String outFile = "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/StoreCADState.out";
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectInputStream in = new ObjectInputStream(new FileInputStream(outFile));
List<Class<? extends Shape>> shapeTypes = (List<Class<? extends Shape>>)in.readObject();
Line.derializeStaticState(in);
List<Shape> shapes = (List<Shape>) in.readObject();
System.out.println(shapes);
}
}
/*
[class io.Circlecolor[1] xPos[70] yPos[7] dim[19]
, class io.Squarecolor[0] xPos[86] yPos[65] dim[56]
, class io.Linecolor[3] xPos[36] yPos[56] dim[20]
, class io.Circlecolor[1] xPos[94] yPos[35] dim[0]
, class io.Squarecolor[0] xPos[41] yPos[99] dim[88]
, class io.Linecolor[3] xPos[64] yPos[69] dim[79]
, class io.Circlecolor[1] xPos[53] yPos[21] dim[19]
, class io.Squarecolor[0] xPos[28] yPos[86] dim[75]
, class io.Linecolor[3] xPos[90] yPos[85] dim[16]
, class io.Circlecolor[1] xPos[20] yPos[65] dim[63]
]
*/
13 XML
对象序列化 只是java的解决方案,只有java程序才能反序列化。
XML太流行,用XML编程的选择太多,包括JDK的javax.xml.*
我们选择开源的XOM类库,最简单,直观 产生和修改XML,并强调XML的正确性。
<dependency>
<groupId>xom</groupId>
<artifactId>xom</artifactId>
<version>1.3.2</version>
</dependency>
package io;
import nu.xom.*;
import java.io.*;
import java.util.*;
public class Person {
private String first,last;
public Person(String first,String last){
this.first =first;
this.last = last;
}
// 从这个Person对象生成XML元素
public Element getXML(){
Element person = new Element("person");
Element firstName = new Element("first");
firstName.appendChild(first);
Element lastName = new Element("last");
lastName.appendChild(last);
person.appendChild(firstName);
person.appendChild(lastName);
return person;
}
// 从XML 还原 Person
public Person(Element person){
first = person.getFirstChildElement("first").getValue();
last = person.getFirstChildElement("last").getValue();
}
public String toString(){ return first + " " + last; }
public static void format(OutputStream os,Document doc) throws IOException {
Serializer serializer = new Serializer(os,"ISO-8859-1");
serializer.setIndent(4);
serializer.setMaxLength(60);
serializer.write(doc);
serializer.flush();
}
static String outPath = "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/Person.xml";
public static void main(String[] args) throws IOException {
List<Person> people = Arrays.asList(
new Person("Dr. Bunsen", "Honeydew"),
new Person("Gonzo","The Great"),
new Person("Phillip J.", "Fry")
);
System.out.println(people);
Element root = new Element("people");
for (Person p: people)
root.appendChild(p.getXML());
Document doc = new Document(root);
format(System.out,doc);
format(new BufferedOutputStream(new FileOutputStream(outPath)),doc);
}
}
/*
[Dr. Bunsen Honeydew, Gonzo The Great, Phillip J. Fry]
<?xml version="1.0" encoding="ISO-8859-1"?>
<people>
<person>
<first>Dr. Bunsen</first>
<last>Honeydew</last>
</person>
<person>
<first>Gonzo</first>
<last>The Great</last>
</person>
<person>
<first>Phillip J.</first>
<last>Fry</last>
</person>
</people>
*/
反序列化Person
package io;
import nu.xom.*;
import java.io.IOException;
import java.util.ArrayList;
public class People extends ArrayList<Person> {
public People(String fileName) throws Exception {
Document doc = new Builder().build(fileName);
Elements elements = doc.getRootElement().getChildElements();
for (int i = 0; i < elements.size();i++)
add(new Person(elements.get(i)));
}
static String outPath = "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/Person.xml";
public static void main(String[] args) throws Exception {
People p = new People(outPath);
System.out.println(p);
}
}
/*
[Dr. Bunsen Honeydew, Gonzo The Great, Phillip J. Fry]
*/
14 Preferences
自动存储和读取信息,用于小的,受限的数据集合。
只能存储基本类型和字符串,且每个字符串长度不能超过8K
用于存储和读取用户偏好及程序配置项的设置
package io;
import java.util.prefs.Preferences;
public class PreferencesDemo {
public static void main(String[] args) throws Exception {
// systemNodeForPackage 通用的安装配置 userNodeForPackage 个别用户的偏好
Preferences prefs = Preferences.userNodeForPackage(PreferencesDemo.class);//标识结点 非静态方法中,通常使用getClass
prefs.put("Location","Oz");
prefs.put("Footwear","Ruby Slippers");
prefs.putInt("Companions",4);
prefs.putBoolean("Are there witches?",true);
int usageCount = prefs.getInt("UsageCount",0);
usageCount++;
prefs.putInt("UsageCount",usageCount);//每运行一次会增加,windows 存注册表 mac 存 /Users/erin/Library/Preferences/com.apple.java.util.prefs.plist
for (String key: prefs.keys())
System.out.println(key + ":" + prefs.get(key,null));
System.out.println("How many companions does Dorothy hava ?" + prefs.getInt("Companions",0 ));
}
}
/*
Footwear:Ruby Slippers
Are there witches?:true
Location:Oz
Companions:4
UsageCount:4
How many companions does Dorothy hava ?4
*/
15 总结
控制台,文件,内存块,网络