Step By Step(Java 输入输出篇)

时间:2020-11-27 22:17:57

    1.    InputStream/OutputStream的字节流家族:
    在C++的标准库中也同样存在这样一个流家族,他们是以iostream为接口,不同的子类提供不同的输出介质,如ifstream和ofstream分别是指向文件的输入输出流,然而C++的标准库为其开发者提供的接口功能也是相对有限的,因此很多的开发者经常会选择使用crt中提供的标准文件输入输出等,如fopen、fclose、fread和fwrite等。与此相比,Java的Framework确实更胜一筹,为其开发者提供了大量的实现类和接口功能,同时也精心设计整个输入输出框架,最为突出的就是基于装饰者(Decoration)模式的接口嵌套机制,他为使用者带来了极为灵活可扩展性。这里将逐一列出InputStream/OutputStream家族的主要成员:
    1) FileInputStream/FileOutputStream: 基于文件作为底层输入输出介质的流对象。

 1     //example 1: 复制文件示例
2 public static void main(String[] args) {
3 FileInputStream fis = null;
4 FileOutputStream fos = null;
5 try {
6 fis = new FileInputStream("D:/memcached-tool.pl");
7 fos = new FileOutputStream("D:/memcached-tool_bak.pl");
8 int b;
9 while ((b = fis.read()) != -1)
10 fos.write(b);
11 } catch (FileNotFoundException e) {
12 } catch (IOException e) {
13 } finally {
14 //需要确保资源能够在程序退出之前被主动的释放或关闭
15 try {
16 fis.close();
17 fos.close();
18 } catch (IOException e) {
19 }
20 }
21 }
22 //example 2: 将字符串写入文件示例
23 public static void main(String[] args) {
24 String strFilePath = "D:/test.txt";
25 FileOutputStream fos = null;
26 try {
27 fos = new FileOutputStream(strFilePath);
28 String strContent = "Write File using Java FileOutputStream example !";
29 fos.write(strContent.getBytes());
30 } catch (FileNotFoundException e) {
31 } catch (IOException e) {
32 } finally {
33 try {
34 fos.close();
35 } catch (IOException e) {
36 }
37 }
38 }
39 //example 3: 拆分文件示例
40 public static void main(String[] args) {
41 FileInputStream fis = null;
42 FileOutputStream fos = null;
43 try {
44 fis = new FileInputStream("D:/memcached-tool.pl");
45 int size = 1024;
46 byte buffer[] = new byte[size];
47
48 int count = 0;
49 while (true) {
50 int i = fis.read(buffer,0,size);
51 if (i == -1)
52 break;
53 String filename = "D:/memcached-tool" + count + ".pl";
54 fos = new FileOutputStream(filename);
55 fos.write(buffer,0,i);
56 fos.flush();
57 fos.close();
58 ++count;
59 }
60 } catch (FileNotFoundException e) {
61 } catch (IOException e) {
62 } finally {
63 try {
64 fis.close();
65 } catch (IOException e) {
66 }
67 }
68 }
69 //example 4: 每隔一个字节读取一个字节,并显示其十六进制值
70 public static void main(String[] args) throws IOException {
71 FileInputStream fin = new FileInputStream("D:/memcached-tool.pl");
72 int len;
73 byte data[] = new byte[16];
74 do {
75 len = fin.read(data);
76 fin.skip(1);
77 for (int j = 0; j < len; j++)
78 System.out.printf("%02X ", data[j]);
79 } while (len != -1);
80 fin.close();
81 }

    2)    BufferedInputStream/BufferedOutputStream: 装饰者模式的最好体现。

 1     //example 1: 和FileInputStream/FileOutputStream的连用。
2 public static void main(String[] args) throws IOException {
3 FileOutputStream fos = new FileOutputStream("D:/test.txt");
4 BufferedOutputStream bos = new BufferedOutputStream(fos);
5 bos.write("this is a test".getBytes());
6 for (int i = 65; i < 75; ++i)
7 bos.write(i);
8 bos.flush();
9 bos.close();
10 }
11 //example 2: 复制文件
12 public static void main(String[] args) throws IOException {
13 FileInputStream fis = new FileInputStream("D:/memcached-tool.pl");
14 BufferedInputStream bis = new BufferedInputStream(fis);
15 FileOutputStream fos = new FileOutputStream("D:/memcached-tool_bak.pl");
16 BufferedOutputStream bos = new BufferedOutputStream(fos);
17 int b;
18 while ((b = bis.read()) != -1)
19 bos.write(b);
20 //这里如果最外层的InputStream/OutputStream关闭了,如果他包含
21 //底层的流对象,那么该底层对象也将被一起关闭,如本例的fis、fos。
22 bos.close();
23 bis.close();
24 }

    3)    ByteArrayOutputStream/ByteArrayInputStream: 通常用于将byte数组视为介质,如从Socket读取的数据可能会直接的填入byte数组,此时则可以使用统一的InputStream/OutputStream接口将数据读出,一旦今后数据源该FileInputStream/FileOutputStream 上层逻辑代码将会保持不变,只是替换底层的介质就可以了,这样便大大缩小了程序修改的范围。

 1     //example 1: 从ByteArrayInputStream读取String
2 public static void main(String[] args) {
3 String tmp = "abc";
4 ByteArrayInputStream in = new ByteArrayInputStream(tmp.getBytes());
5 for (int i = 0; i < 2; i++) {
6 int c;
7 while ((c = in.read()) != -1) {
8 if (i == 0)
9 System.out.print((char) c);
10 else
11 System.out.print(Character.toUpperCase((char)c));
12 }
13 System.out.println();
14 in.reset();
15 }
16 }
17 //example 2: 交互使用ByteArrayOutputStream和ByteArrayInputStream
18 public static void main(String[] args) {
19 String s = "This is a test.";
20 ByteArrayOutputStream outStream = new ByteArrayOutputStream(s.getBytes().length);
21 for (int i = 0; i < s.length(); ++i)
22 outStream.write(s.charAt(i));
23 System.out.println("outstream: " + outStream);
24 System.out.println("size: " + outStream.size());
25
26 ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray());
27 int inBytes = inStream.available();
28 System.out.println("inStream has " + inBytes + " available bytes");
29 byte inBuf[] = new byte[inBytes];
30 int bytesRead = inStream.read(inBuf, 0, inBytes);
31 System.out.println(bytesRead + " bytes were read");
32 System.out.println("They are: " + new String(inBuf));
33 }

    4)    DataInputStream/DataOutputStream: 提供了基于类型的输入输出的接口功能,当与C/C++服务程序通过Socket进行通讯时,如果不使用nio,通过数据输入输出流结合字节数组输入输出流,将int、long、float等原始类型的数据通过DataInputStream/DataOutputStream提供的方便接口写入底层的字节数组,在直接发送给remote的C/C++服务程序,在实际的开发中这样的应用确实带来了一定的便利。

 1     //example 1: 套接FileInputStream/FileOutputStream将原始类型的数据写入和读出文件
2 public static void main(String[] args) throws IOException {
3 FileOutputStream fileOut = new FileOutputStream("D:/data.txt");
4 DataOutputStream dataOut = new DataOutputStream(fileOut);
5 for (int i = 0; i < 10; ++i)
6 dataOut.writeInt(i);
7 double d = 0.0;
8 for (int i = 0; i < 10; ++i)
9 dataOut.writeDouble(d + i);
10 dataOut.writeBoolean(true);
11 dataOut.writeBoolean(false);
12 String[] descs = { "Java T-shirt", "Java Mug",
13 "Duke Juggling Dolls", "Java Pin", "Java Key Chain" };
14 for (int i = 0; i < descs.length; ++i)
15 dataOut.writeUTF(descs[i]);
16 dataOut.close();
17
18 FileInputStream fileIn = new FileInputStream("D:/data.txt");
19 DataInputStream dataIn = new DataInputStream(fileIn);
20 int intTotal = 0;
21 for (int i = 0; i < 10; ++i)
22 intTotal += dataIn.readInt();
23 double doubleTotal = 0.0;
24 for (int i = 0; i < 10; ++i)
25 doubleTotal += dataIn.readDouble();
26 boolean b1 = dataIn.readBoolean();
27 boolean b2 = dataIn.readBoolean();
28 System.out.println("TotalInt = " + intTotal);
29 System.out.println("TotalDouble = " + doubleTotal);
30 System.out.println("b1 = " + b1);
31 System.out.println("b2 = " + b2);
32 for (int i = 0; i < descs.length; ++i)
33 System.out.println("desc[" + i + "] = " + dataIn.readUTF());
34 dataIn.close();
35
36 File f = new File("D:/data.txt");
37 f.delete();
38 }

    5)    InflaterInputStream/DeflaterOutputStream:

 1     public static void main(String[] args) throws IOException {
2 double data[] = { 1.1, 2.2, 3.3, 4.4, 5.5, 6.6 };
3 ByteArrayOutputStream bout = new ByteArrayOutputStream(data.length * 8);
4 DataOutputStream dout = new DataOutputStream(new DeflaterOutputStream(bout));
5 dout.writeInt(data.length);
6 for (double d : data)
7 dout.writeDouble(d);
8 dout.close();
9
10 ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
11 DataInputStream din = new DataInputStream(new InflaterInputStream(bin));
12 int num = din.readInt();
13 double avg = 0.0;
14 double d;
15 for (int i = 0; i < num; ++i) {
16 d = din.readDouble();
17 avg += d;
18 System.out.print(d + " ");
19 }
20 din.close();
21 }

    6)    GZIPOutputStream/GZIPInputStream: 基于GZIP规则压缩

 1     public static void main(String[] args) throws IOException {
2 GZIPOutputStream out = new GZIPOutputStream(new FileOutputStream("D:/memcached-tool.gzip"));
3 FileInputStream in = new FileInputStream("D:/memcached-tool.pl");
4 byte[] buf = new byte[1024];
5 int len;
6 while ((len = in.read(buf)) > 0)
7 out.write(buf, 0, len);
8 in.close();
9 out.finish();
10 out.close();
11
12 GZIPInputStream gin = new GZIPInputStream(new FileInputStream("D:/memcached-tool.gzip"));
13 FileOutputStream fout = new FileOutputStream("D:/memcached-tool_bak.pl");
14 int b;
15 while ((b = gin.read()) != -1)
16 fout.write(b);
17 gin.close();
18 fout.close();
19 }

    7)    ZipInputStream/ZipOutputStream/ZipFile: 按照标准zip的格式压缩和解压文件。

 1     public static void main(String[] args) throws IOException {
2 // 1. 压缩文件:
3 // 1.1 写入源文件条目信息
4 // 1.2 写入源文件数据
5 String[] filenames = new String[] { "D:/memcached-tool.pl", "D:/memcached-tool1.pl" };
6 byte[] buf = new byte[1024];
7 String zipFilename = "D:/outfile.zip";
8 ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFilename));
9 for (int i = 0; i < filenames.length; ++i) {
10 FileInputStream in = new FileInputStream(filenames[i]);
11 // 写入源文件条目信息
12 out.putNextEntry(new ZipEntry(filenames[i]));
13 int len;
14 // 开始写数据了。
15 while ((len = in.read(buf)) > 0)
16 out.write(buf, 0, len);
17 out.closeEntry();
18 in.close();
19 }
20 out.close();
21 // 2. 扫描zip文件中已经压缩文件的条目信息
22 ZipFile zf = new ZipFile(zipFilename);
23 for (Enumeration entries = zf.entries(); entries.hasMoreElements();) {
24 String zipEntryName = ((ZipEntry)entries.nextElement()).getName();
25 System.out.println("Filename = " + zipEntryName);
26 }
27 // 3. 解压缩文件
28 // 3.1 读取出压缩文件的条目信息
29 // 3.2 读取出压缩文件的数据
30 Enumeration<? extends ZipEntry> files = zf.entries();
31 while (files.hasMoreElements()) {
32 ZipEntry ze = files.nextElement();
33 System.out.println("Decompressing " + ze.getName());
34 System.out.println("Compressed Size: " + ze.getCompressedSize()
35 + " Expanded Size: " + ze.getSize() + "\n");
36 BufferedInputStream bin = new BufferedInputStream(zf.getInputStream(ze));
37 BufferedOutputStream bout = new BufferedOutputStream(
38 new FileOutputStream(ze.getName() + ".zip"));
39 int i;
40 do {
41 i = bin.read();
42 if (i != -1)
43 bout.write(i);
44 } while (i != -1);
45 bout.close();
46 bin.close();
47 }
48 zf.close();
49 }

    8)    PrintStream: 提供了一些方便的打印输出格式化的功能

1     public static void main(String[] args) throws IOException {
2 PrintStream p = new PrintStream(new FileOutputStream("D:/1.txt",false));
3 int i = 4;
4 p.print(i);
5 p.println("HelloWorld");
6 p.format("The final %d\n", i);
7 p.close();
8 }

    9)    标准输入输出流的重定向

 1     //将标准输出和错误输出进行了重新定向。
2 public static void main(String[] args) throws IOException {
3 System.setOut(new LogStream(System.out,new PrintStream(
4 new FileOutputStream("D:/out.log"))));
5 System.setErr(new LogStream(System.err,new PrintStream(
6 new FileOutputStream("D:/err.log"))));
7 System.out.println("output");
8 System.err.println("error");
9 }
10 class LogStream extends PrintStream {
11 PrintStream out;
12 //可以同时输出到两个流
13 public LogStream(PrintStream out1, PrintStream out2) {
14 super(out1);
15 this.out = out2;
16 }
17 public void write(byte buf[], int off, int len) {
18 try {
19 super.write(buf, off, len);
20 out.write(buf, off, len);
21 } catch (Exception e) {
22 }
23 }
24 public void flush() {
25 super.flush();
26 out.flush();
27 }
28 }

    2.    Reader/Writer的字符流家族:
    1)    FileReader/FileWriter: 以文件作为底层介质的字符流对象。

 1     //example 1: 标准的读出和写入
2 public static void main(String[] args) throws IOException {
3 Reader in = new FileReader("D:/memcached-tool.pl");
4 Writer out = new FileWriter("D:/memcached-tool1.pl");
5 int c;
6 while ((c = in.read()) != -1)
7 out.write(c);
8 in.close();
9 out.close();
10 }
11 //example 2: 整行读入到String
12 public static void main(String[] args) throws IOException {
13 FileReader fr = new FileReader("D:/memcached-tool.pl");
14 BufferedReader br = new BufferedReader(fr);
15 String line;
16 while ((line = br.readLine()) != null) {
17 char array[] = line.toCharArray();
18 System.out.println(array);
19 }
20 }

    2)    BufferedReader/BufferedWriter: 相对于字节流中的BufferedInputStream/BufferedOutputStream。

 1     public static void main(String[] args) throws IOException {
2 BufferedReader br = new BufferedReader(new FileReader("D:/memcached-tool.pl"));
3 BufferedWriter bw = new BufferedWriter(new FileWriter("D:/memcached-tool1.pl"));
4 String s;
5 //readLine的返回结果不包括结尾的\r\n,因此在回写的时候需要重新加入
6 while ((s = br.readLine()) != null) {
7 bw.write(s);
8 bw.newLine();
9 }
10 bw.close();
11 bw.close();
12 }

    3)    CharArrayReader/CharArrayWrite: 对应于字节流中的ByteArrayInputStream/ByteArrayOutputStream。

 1     public static void main(String[] args) throws IOException {
2 CharArrayWriter outStream = new CharArrayWriter();
3 String s = "This is a test.";
4 for (int i = 0; i < s.length(); ++i)
5 outStream.write(s.charAt(i));
6 System.out.println("outstream: " + outStream);
7 System.out.println("size: " + outStream.size());
8 CharArrayReader inStream = new CharArrayReader(outStream.toCharArray());
9 int ch = 0;
10 StringBuffer sb = new StringBuffer("");
11 while ((ch = inStream.read()) != -1)
12 sb.append((char) ch);
13 s = sb.toString();
14 System.out.println(s.length() + " characters were read");
15 System.out.println("They are: " + s);
16 }

    4)    StringReader/StringWriter: 从字符串中读取或写入到底层的StringBuffer中。

 1     public static void main(String[] args) throws IOException {
2 StringWriter outStream = new StringWriter();
3 String s = "This is a test.";
4 for (int i = 0; i < s.length(); ++i)
5 outStream.write(s.charAt(i));
6 System.out.println("outstream: " + outStream);
7 System.out.println("size: " + outStream.toString().length());
8 StringReader inStream = new StringReader(outStream.toString());
9 int ch = 0;
10 StringBuffer sb = new StringBuffer("");
11 while ((ch = inStream.read()) != -1)
12 sb.append((char)ch);
13 s = sb.toString();
14 System.out.println(s.length() + " characters were read");
15 System.out.println("They are: " + s);
16 }

    5)    PrintWriter: 对应于前面给出的打印字节流PrintStream

 1     public static void main(String[] args) throws IOException {
2 PrintWriter pw = new PrintWriter(System.out);
3 pw.println(true);
4 pw.println('A');
5 pw.println(500);
6 pw.println(40000L);
7 pw.println(45.67f);
8 pw.println(45.67);
9 pw.println("Hello");
10 pw.println(new Integer("99"));
11 for (int i = 0; i < 3; ++i)
12 pw.format("The id = %d.\n", i);
13 pw.close();
14 }

    6)    LineNumberReader: 整行读取并可以获取行号。

1     public static void main(String[] args) throws IOException {
2 LineNumberReader r = new LineNumberReader(
3 new FileReader("D:/memcached-tool_new.pl"));
4 String line = null;
5 while ((line = r.readLine()) != null)
6 System.out.println(r.getLineNumber() + ": " + line);
7 r.close();
8 }

    3.    字节流和字符流之间的转换:

 1     public static void main(String[] args) throws IOException {
2 InputStreamReader isr = new InputStreamReader(new FileInputStream("D:/1.txt"));
3 BufferedReader br = new BufferedReader(isr);
4 String s;
5 OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:/2.txt"));
6 while ((s = br.readLine()) != null) {
7 System.out.println(s);
8 osw.write(s);
9 osw.write(System.getProperty("line.separator"));
10 }
11 isr.close();
12 osw.close();
13 }

    4.    Scanner: 扫描器类。可以读取字符流,兼具StreamTokenizer拆分字符流和StreamDataInputStream直接读取原始数据类型的功能。

 1     public static void main(String[] args) throws IOException {
2 String filename = "D:/1.txt";
3 FileOutputStream fout = new FileOutputStream(filename);
4 String str = "1 hello true 1.00 A ";
5 fout.write(str.getBytes());
6 fout.write(System.getProperty("line.separator").getBytes());
7 String str2 = "2,world,false,1.0,B";
8 fout.write(str2.getBytes());
9 fout.close();
10 Scanner scanner = new Scanner(new File(filename));
11 //通过正则的模式设置分隔符
12 scanner.useDelimiter("[\t| |,]");
13 while (scanner.hasNext())
14 System.out.println(scanner.next());
15 scanner.close();
16
17 fout = new FileOutputStream(filename);
18 str2 = "2,world,false,1.0,B";
19 fout.write(str2.getBytes());
20 scanner = new Scanner(new File(filename));
21 scanner.useDelimiter(",");
22 if (scanner.hasNextInt())
23 System.out.println("nextInt = " + scanner.nextInt());
24 if (scanner.hasNext())
25 System.out.println("next = " + scanner.next());
26 if (scanner.hasNextBoolean())
27 System.out.println("nextBoolean = " + scanner.nextBoolean());
28 if (scanner.hasNextDouble())
29 System.out.println("nextDouble = " + scanner.nextDouble());
30 if (scanner.hasNext())
31 System.out.println("nextByte = " + scanner.next());
32 scanner.close();
33 }

    5.    文件操作:在Java中提供了File类,用于完成各种和File相关的操作,需要注意的是JDK并没有提供Directory的类来表示目录,而是通过File中的isDirectory()方法的返回结果来确实当前File对象实例是否代表一个目录。文件的常用代码示例如下:

 1     //example 1: 
2 //createNewFile
3 public static void main(String[] args) {
4 new File("D:/File").mkdir();
5 File file = new File("D:/File/Demo.txt");
6 try {
7 file.createNewFile();
8 FileOutputStream os = new FileOutputStream(file);
9 FileDescriptor fd = os.getFD();
10 os.write('1');
11 os.flush();
12 fd.sync();
13 } catch (IOException e) {
14 }
15 }
16 //example 2:
17 //renameTo
18 //exists/delete
19 //setReadOnly/canWrite/isHidden
20 //setLastModified/lastModified
21 public static void main(String[] args) {
22 File oldName = new File("D:/memcached-tool.pl");
23 File newName = new File("D:/memcached-tool_new.pl");
24 if (newName.exists()) {
25 newName.delete();
26 }
27 if (oldName.renameTo(newName)) {
28 System.out.println("renamed");
29 } else {
30 System.out.println("Error");
31 }
32 File readonlyFile = new File("D:/memcached-tool_new.pl");
33 Calendar c = GregorianCalendar.getInstance();
34 System.out.println(readonlyFile.setLastModified(c.getTime().getTime()));
35 System.out.println(new Date(readonlyFile.lastModified()));
36 System.out.println(readonlyFile.setReadOnly());
37 System.out.println(readonlyFile.canWrite());
38 System.out.println(readonlyFile.isHidden());
39 }
40 //example 3: 获取文件的size
41 public static void main(String[] args) {
42 File file = new File("D:/memcached-tool_new.pl");
43 long fileSize = file.length();
44 System.out.println(fileSize + " bytes");
45 System.out.println((double) fileSize / 1024 + " KB");
46 System.out.println((double) fileSize / (1024 * 1024) + "MB");
47 }
48 //example 4: 磁盘驱动器信息getTotalSpace/getUsableSpace/getFreeSpace
49 public static void main(String[] args) {
50 File[] roots = File.listRoots();
51 for (int i = 0; i < roots.length; i++) {
52 System.out.println("Partition: " + roots[i]);
53 System.out.println("Total space = " + roots[i].getTotalSpace());
54 System.out.println("Usable space = " + roots[i].getUsableSpace());
55 System.out.println("Free space = " + roots[i].getFreeSpace());
56 }
57 }
58 //example 5: 文件名过滤器
59 public static void main(String[] args) {
60 File dir = new File("D:/Test");
61 FilenameFilter filter = new FilenameFilter() {
62 public boolean accept(File dir, String name) {
63 return name.endsWith("pl");
64 }
65 };
66 String[] children = dir.list(filter);
67 for (String s : children)
68 System.out.println(s);
69 }
70 //example 6: 文件过滤器
71 public static void main(String[] args) {
72 File dir = new File("D:/Documents");
73 FileFilter fileFilter = new FileFilter() {
74 public boolean accept(File file) {
75 return file.isDirectory();
76 }
77 };
78 File[] files = dir.listFiles(fileFilter);
79 for (File f : files)
80 System.out.println(f.getPath());
81 }

    6.    目录操作:如第5条所述,这里的目录操作仍然需要使用File类。

 1     //example 1: 规格化目录的相对路径之后,再判断两个目录是否指向同一目录
2 public static void main(String[] args) throws Exception {
3 File file1 = new File("./filename");
4 File file2 = new File("filename");
5 System.out.println(file1.equals(file2));
6
7 file1 = file1.getCanonicalFile();
8 file2 = file2.getCanonicalFile();
9 System.out.println(file1.equals(file2));
10 }
11 //example 2: 获取当前目录,递归该目录下的所有文件
12 public static void main(String[] argv) throws Exception {
13 File currentDir = new File(System.getProperty("user.dir"));
14 visitAllFiles(currentDir);
15 }
16 public static void visitAllFiles(File dir) {
17 if (dir.isDirectory()) {
18 String[] children = dir.list();
19 for (int i = 0; i < children.length; i++)
20 visitAllFiles(new File(dir, children[i]));
21 } else {
22 System.out.println(dir);
23 }
24 }
25 //example 3:
26 //getParent/getName/getPath/getParentFile
27 //mkdir/mkdirs/delete
28 public static void main(String[] args) {
29 File dir = new File("D:/Demo");
30 System.out.println(dir.mkdir());
31 File dir1 = new File("D:/Demo/Demo2");
32 // 如果父目录不存在,则递归的创建父目录和当前目录。
33 System.out.println(dir.mkdirs());
34 File file = new File("D:/File/Demo.txt");
35 System.out.println(file.getParent());
36 System.out.println(file.getName());
37 System.out.println(file.getPath());
38 File fileParent = file.getParentFile();
39 System.out.println("Parent directory: " + fileParent.getPath());
40 dir.delete();
41 }

    7.    文件锁:通常会存在这样一种应用,既多个不同的进程协同工作,其中一个进程负责将原始数据文件中的数据格式化成系统标准的数据文件格式,并将格式化后的文件存放到指定的目录中,而另外一个进程则负责解析这个标准格式的文件,并将解析后的数据根据实际业务的规则,筛选后加载到Oracle中。在这样的应用场景中,两个进程需要一定的同步,否则当第一个进程只是copy部分数据的时候,第二个进程就可能开始读取并加载了。在C++中,常用的方法是利用操作系统提供的用于进程间同步的信号量机制,来协调两个进程共同完成该项工作。在Java中,JDK提供了文件锁的机制也是可以实现这一目标的,然而由于文件锁是高度依赖操作系统特征的,因此应该尽量避免以下两种使用方式的

    1)  文件锁是用整个虚拟机持有的。如果有两个程序是由同一个虚拟机启动的,那么它们不可能每一个都获得一个在同一个文件上的锁。当调用lock和tryLock方法时,如果虚拟机已经在同一个文件上持有了另一个重叠的锁,那么着两个方法将抛出OverlappingFileLockException异常。

    2)  在一些系统中,关闭一个通道会释放由Java虚拟机持有的潜在文件上的所有锁。因此,在同一个加锁文件上应避免使用多个锁。

    文件锁的通常使用方式见如下示例代码:

 1     public static void main(String[] args) throws IOException {
2 File file = new File("D:/memcached-tool.pl");
3 FileChannel channel = new RandomAccessFile(file, "rw").getChannel();
4 //tryLock的最后一个参数为true,表示本次获取的是共享文件锁,否则就是独占锁。
5 FileLock lock = channel.tryLock(0, Long.MAX_VALUE, true);
6 try {
7 Thread.sleep(1000);
8 } catch (InterruptedException e) {
9 }
10 lock.release();
11 channel.close();
12 }

    8.    随机存取文件:

 1     //example 1: 反向输出文件
2 public static void main(String[] args) throws IOException {
3 RandomAccessFile raf = new RandomAccessFile("D:/memcached-tool.pl", "r");
4 long position = raf.length();
5 while (position > 0) {
6 position -= 1;
7 raf.seek(position);
8 byte b = raf.readByte();
9 System.out.print((char) b);
10 }
11 }
12 //example 2: 追加数据到文件的末尾
13 public static void append(String fileName, String text) throws Exception {
14 File f = new File(fileName);
15 long fileLength = f.length();
16 RandomAccessFile raf = new RandomAccessFile(f, "rw");
17 raf.seek(fileLength);
18 raf.writeBytes(text);
19 raf.close();
20 }
21 public static void append(String fileName, byte[] bytes) throws Exception {
22 File f = new File(fileName);
23 long fileLength = f.length();
24 RandomAccessFile raf = new RandomAccessFile(f, "rw");
25 raf.seek(fileLength);
26 raf.write(bytes);
27 raf.close();
28 }
29 public static void main(String[] args) throws Exception {
30 append("D:/tmp.txt", "Appended Data");
31 append("D:/tmp.bin", "Appended Data".getBytes());
32 }
33 //example 3: 正常读写文件
34 public static void main(String[] args) throws Exception {
35 RandomAccessFile raf = new RandomAccessFile("D:/employee.dat", "rw");
36 raf.writeUTF("J");
37 System.out.println("The current position is " + raf.getFilePointer());
38 raf.writeUTF("S");
39 System.out.println("The current position is " + raf.getFilePointer());
40 raf.writeDouble(4.0);
41 System.out.println("The current position is " + raf.getFilePointer());
42 raf.seek(0L);
43 String fname = raf.readUTF();
44 System.out.println("The current position is " + raf.getFilePointer());
45 String lname = raf.readUTF();
46 System.out.println("The current position is " + raf.getFilePointer());
47 double salary = raf.readDouble();
48 System.out.println("The current position is " + raf.getFilePointer());
49 System.out.println("First name = " + fname);
50 System.out.println("Last name = " + lname);
51 System.out.println("Salary = " + salary);
52 raf.close();
53 }
54 //example 4: 从文件中直接读写各种原始类型
55 public static void main(String[] args) throws Exception {
56 RandomAccessFile file = new RandomAccessFile("D:/test.txt", "rw");
57 file.writeBoolean(true);
58 file.writeInt(123456);
59 file.writeChar('j');
60 file.writeDouble(1234.56);
61 file.seek(1);
62 System.out.println(file.readInt());
63 System.out.println(file.readChar());
64 System.out.println(file.readDouble());
65 file.seek(0);
66 System.out.println(file.readBoolean());
67 file.close();
68 }

    9.    NIO:Java在JDK 1.4 中推出了一套基于异步的高效的IO操作包--nio,其主要应用于文件和Socket的操作。这里先简单介绍一下NIO中最重要的一组classes(缓冲区对象)的使用方式,这里仅以ByteBuffer为例,其他类型的Buffer,如CharBuffer、IntBuffer和ShortBuffer等基本雷同:
    1)   boolean hasRemaining(): 如果当前的缓冲区位置没有达到这个缓冲区的界限位置则返回true。
    2)   int limit(): 返回这个缓冲区的界限位置,即没有任何值可用的第一个位置。
    3)    byte get(): 从当前位置获得一个字节,并将当前位置推到下一个字节。
    4)    byte get(int index): 从指定索引处获得一个字节。
    5)    ByteBuffer put(byte b): 向当前位置推入一个字节,并将当前位置推到下一个字节。
    6)    ByteBuffer put(int index, byte b): 向指定索引处推入一个字节。
    7)    Xxx getXxx()/Xxx getXxx(int index)/ByteBuffer putXxx(xxx value)/ByteBuffer putXxx(int index,xxx value):获取或放置一个二进制数。Xxx Int/Long/Short/Char/Float/Double。
    8)    ByteBuffer order(ByteOrder order)/ByteOrder order(): 设置或获取字节顺序,order的值是ByteOrder类的常量BIG_ENDIAN/LITTLE_ENDIAN中的一个。
    9) Buffer clear(): 通过将位置复位到0,并将界限复位到容量,使这个缓冲区为写出做好准备。
    10) Buffer flip(): 通过将界限设置到位置,并将位置复位到0,使这个缓冲区为读入做好准备。
    11) Buffer rewind(): 通过将读写位置复位到0,并保持极限不变,使这个缓冲区为重新读入相同的值做好准备。
    12) Buffer mark(): 将这个缓冲区的标记设置到读写位置。
    13) Buffer reset(): 将这个缓冲区的位置设置到标记,从而允许被标记的部分可以再次被读入或写出。
    14) remaining(): 返回剩余可读入或写出的值的数量,即边界与位置之间的差异。
    15) int position(): 返回这个缓冲区的位置。
    16) int capacity(): 返回这个缓冲区的容量。
    以下为nio的常用示例:

  1     //example 1: 
2 //比较nio和io在copy文件上的使用差别及运行时的效率差别,在我的例子中
3 //使用的文件是80M左右,从输出结果看nio效率好于io,以下为输出结果
4 // nio.copy = 3490
5 // io.copy = 4891
6 public class MyTest {
7 static int size = 60; // MB
8 static int tests = 5;
9 interface Copier {
10 public void copy(File s, File t) throws IOException;
11 }
12 static class NioCopier implements Copier {
13 public void copy(File s, File t) throws IOException {
14 FileChannel in = (new FileInputStream(s)).getChannel();
15 FileChannel out = (new FileOutputStream(t)).getChannel();
16 in.transferTo(0, s.length(), out);
17 in.close();
18 out.close();
19 }
20 }
21 static class IoCopier implements Copier {
22 final int BUFF_SIZE = 5 * 1024 * 1024; // 5MB
23 final byte[] buffer = new byte[BUFF_SIZE];
24 public void copy(File s, File t) throws IOException {
25 InputStream in = new FileInputStream(s);
26 FileOutputStream out = new FileOutputStream(t);
27
28 while (true) {
29 int count = in.read(buffer);
30 if (count == -1)
31 break;
32 out.write(buffer, 0, count);
33 }
34 out.close();
35 in.close();
36 }
37 }
38 public static void main(String[] args) throws IOException {
39 Copier io = new IoCopier();
40 Copier nio = new NioCopier();
41 long start = System.currentTimeMillis();
42 nio.copy(new File("D:/1.rar"), new File("D:/2.rar"));
43 System.out.println("nio.copy = " + (System.currentTimeMillis() - start));
44 start = System.currentTimeMillis();
45 io.copy(new File("D:/1.rar"), new File("D:/3.rar"));
46 System.out.println("io.copy = " + (System.currentTimeMillis() - start));
47 }
48 }
49 //example 2: 利用nio从文件输入输出
50 public static void main(String[] args) throws IOException {
51 String source = "D:/memcached-tool.pl";
52 String destination = "D:/memcached-tool_bak.pl";
53 FileInputStream fis = new FileInputStream(source);
54 FileOutputStream fos = new FileOutputStream(destination);
55 // nio部分
56 FileChannel fci = fis.getChannel();
57 FileChannel fco = fos.getChannel();
58 ByteBuffer buffer = ByteBuffer.allocate(1024);
59 while (true) {
60 int read = fci.read(buffer);
61 if (read == -1)
62 break;
63 //flip之后将ByteBuffer的limit设置为当前位置,
64 //position归0,为写出做好了准备。
65 buffer.flip();
66 fco.write(buffer);
67 //clear一般是为下次读做准备
68 buffer.clear();
69 }
70 fis.close();
71 fos.close();
72 }
73 //example 3: 通过nio.FileChannel赋值文件(一块一块的copy)
74 public static void main(String[] args) throws IOException {
75 FileChannel srcChannel = new FileInputStream("D:/memcached-tool.pl").getChannel();
76 FileChannel dstChannel = new FileOutputStream("D:/memcached-tool_bak.pl").getChannel();
77 long total = 0;
78 long count = 0;
79 while (true) {
80 //transferFrom方法极有可能更好的利用了操作系统底层带来的优化
81 //因此其性能要好于普通IO中基于byte[]的传递
82 count = dstChannel.transferFrom(srcChannel,total,1024);
83 total += count;
84 dstChannel.position(total);
85 if (count == 0)
86 break;
87 }
88 srcChannel.close();
89 dstChannel.close();
90 }
91 //example 4: 从ByteBuffer获得不同原始类型的表述
92 public static void main(String[] args) throws IOException {
93 ByteBuffer bb = ByteBuffer.allocate(1024);
94 // Allocation automatically zeroes the ByteBuffer:
95 int i = 0;
96 while (i++ < bb.limit()) {
97 if (bb.get() != 0)
98 System.out.println("nonzero");
99 }
100 System.out.println("i = " + i);
101 bb.rewind();
102 // Store and read a char array:
103 bb.asCharBuffer().put("Howdy!");
104 char c;
105 while ((c = bb.getChar()) != 0)
106 System.out.print(c + " ");
107 System.out.println();
108 bb.rewind();
109 // Store and read a short:
110 bb.asShortBuffer().put((short) 471142);
111 System.out.println(bb.getShort());
112 bb.rewind();
113 // Store and read an int:
114 bb.asIntBuffer().put(99471142);
115 System.out.println(bb.getInt());
116 bb.rewind();
117 // Store and read a long:
118 bb.asLongBuffer().put(99471142);
119 System.out.println(bb.getLong());
120 bb.rewind();
121 // Store and read a float:
122 bb.asFloatBuffer().put(99471142);
123 System.out.println(bb.getFloat());
124 bb.rewind();
125 // Store and read a double:
126 bb.asDoubleBuffer().put(99471142);
127 System.out.println(bb.getDouble());
128 bb.rewind();
129 }
130 //example 5: 操纵ints在ByteBuffer使用IntBuffer
131 public static void main(String[] args) throws IOException {
132 ByteBuffer bb = ByteBuffer.allocate(1024);
133 IntBuffer ib = bb.asIntBuffer();
134 // Store an array of int:
135 ib.put(new int[] { 11, 42, 47, 99, 143, 811, 1016 });
136 // Absolute location read and write:
137 System.out.println(ib.get(3));
138 ib.put(3, 1811);
139 ib.rewind();
140 while (ib.hasRemaining()) {
141 int i = ib.get();
142 if (i == 0)
143 break; // Else we'll get the entire buffer
144 System.out.println(i);
145 }
146 }
147 //example 6: 通过ByteBuffer和ByteOrder,输出不同字节序到byte数组
148 public static void main(String[] args) {
149 ByteBuffer bb = ByteBuffer.wrap(new byte[12]);
150 bb.asCharBuffer().put("abcdef");
151 System.out.println(toString(bb.array()));
152 bb.rewind();
153 bb.order(ByteOrder.BIG_ENDIAN);
154 bb.asCharBuffer().put("abcdef");
155 System.out.println(toString(bb.array()));
156 bb.rewind();
157 bb.order(ByteOrder.LITTLE_ENDIAN);
158 bb.asCharBuffer().put("abcdef");
159 System.out.println(toString(bb.array()));
160 }
161 static String toString(byte[] a) {
162 StringBuffer result = new StringBuffer("[");
163 for (int i = 0; i < a.length; i++) {
164 result.append(a[i]);
165 if (i < a.length - 1)
166 result.append(", ");
167 }
168 result.append("]");
169 return result.toString();
170 }
171 //example 7: 写入ByteBuffer数据,观察前后状态
172 public static void main(String[] args) throws IOException {
173 String phrase = new String("www.java2s.com\n");
174 File aFile = new File("test.txt");
175 FileOutputStream outputFile = null;
176 try {
177 outputFile = new FileOutputStream(aFile, true);
178 System.out.println("File stream created successfully.");
179 } catch (FileNotFoundException e) {
180 }
181
182 FileChannel outChannel = outputFile.getChannel();
183 ByteBuffer buf = ByteBuffer.allocate(1024);
184 System.out.println("New buffer: position = " + buf.position() + "\tLimit = " + buf.limit()
185 + "\tcapacity = " + buf.capacity());
186 // Load the data into the buffer
187 for (char ch : phrase.toCharArray())
188 buf.putChar(ch);
189 System.out.println("Buffer after loading: position = " + buf.position() + "\tLimit = " + buf.limit()
190 + "\tcapacity = " + buf.capacity());
191 buf.flip();
192 System.out.println("Buffer after flip: position = " + buf.position() + "\tLimit = " + buf.limit()
193 + "\tcapacity = " + buf.capacity());
194 try {
195 outChannel.write(buf);
196 outputFile.close();
197 System.out.println("Buffer contents written to file.");
198 } catch (IOException e) {
199 }
200 }
201 //example 8: 通过ByteBuffer写入文件
202 public static void main(String[] args) throws IOException {
203 FileOutputStream fileOutputStream;
204 FileChannel fileChannel;
205 ByteBuffer byteBuffer;
206
207 try {
208 fileOutputStream = new FileOutputStream("D:/test.txt");
209 fileChannel = fileOutputStream.getChannel();
210 byteBuffer = ByteBuffer.allocateDirect(26);
211
212 for (int i = 0; i < 26; i++)
213 byteBuffer.put((byte) ('A' + i));
214 byteBuffer.rewind();
215 fileChannel.write(byteBuffer);
216 fileChannel.close();
217 fileOutputStream.close();
218 } catch (IOException exc) {
219 System.out.println(exc);
220 }
221 }

    10.    使用内存映射文件:该功能源于底层操作系统的支持,如windows、Linux等。主要应用于进程间通讯和进程间的数据共享。

 1     //example 1: 从内存映射文件中读取数据
2 public static void main(String[] args) throws IOException {
3 try {
4 FileInputStream fileInputStream = new FileInputStream("D:/memcached-tool_new.pl");
5 FileChannel fileChannel = fileInputStream.getChannel();
6 long fileSize = fileChannel.size();
7 MappedByteBuffer mBuf = fileChannel.map(FileChannel.MapMode.READ_ONLY,0,fileSize);
8 for (int i = 0; i < fileSize; ++i)
9 System.out.print((char)mBuf.get());
10 fileChannel.close();
11 fileInputStream.close();
12 } catch (IOException exc) {
13 System.out.println(exc);
14 System.exit(1);
15 }
16 }
17 //example 2: 写入数据到内存映射文件
18 public static void main(String[] args) throws IOException {
19 File file = new File("D:/memcached-tool_new.pl");
20 FileChannel channel = new RandomAccessFile(file,"rw").getChannel();
21 MappedByteBuffer buf = channel.map(FileChannel.MapMode.READ_WRITE,0,(int)channel.size());
22 buf.put(0,(byte)0xFF);
23 //强制对内存映射作出的改变刷新到物理文件。
24 buf.force();
25 channel.close();
26 }
27 //example 3: 结合使用nio的FileChannel和MappedByteBuffer拷贝文件
28 public static void main(String[] args) throws IOException {
29 FileInputStream fIn = new FileInputStream("D:/1.txt");
30 FileOutputStream fOut = new FileOutputStream("D:/2.txt");
31 FileChannel fIChan = fIn.getChannel();
32 FileChannel fOChan = fOut.getChannel();
33 long fSize = fIChan.size();
34 MappedByteBuffer mBuf = fIChan.map(FileChannel.MapMode.READ_ONLY, 0, fSize);
35 fOChan.write(mBuf); // this copies the file
36 fIChan.close();
37 fIn.close();
38 fOChan.close();
39 fOut.close();
40 }

     11.    对象序列化:Java依托其强大的反射机制,设计出功能同样强大的对象序列化与反序列化的框架。在C++的标准中,对象生成的模型中并不包含对象的metadata信息(反射的基础数据来源),只是包含了一些非常简单的动态类型信息,以数据段数据的紧凑,同时由于在运行时避免了生成这些附加的信息,从而也确保了程序在运行时的效率。然而,有些C++的类库,如MFC、QT等,通过使用宏定义的方式,既在每个自定义类的声明中使用宏的声明,从而保证了在编译阶段将类的metadata信息写入该自定义类的数据成员内部。

  1     //example 1: 这是最简单也是最常见的对象序列化使用方式。
2 //1. 被序列化的class必须是Serializable实现类
3 //2. 该实现类的域成员或者是原始类型,如int,float,或者也是Serializable的实现类
4 //否则就会抛出不能被序列化的异常,例子中String都是Serializable的实现类。
5 //3. 瞬时类型(transient)和静态的域字段是不会被序列化和反序列化的。
6 class Book implements Serializable {
7 private transient int tt = 0;
8 private String isbn;
9 private String title;
10 private String author;
11 private int kk;
12 public Book(String isbn, String title, String author,int kk,int tt) {
13 this.kk = kk;
14 this.isbn = isbn;
15 this.title = title;
16 this.author = author;
17 this.tt = tt;
18 }
19
20 public String toString() {
21 return "[Book: " + isbn + ", " + title + ", " + author + "," + kk + "," + tt + "]";
22 }
23 }
24 public static void main(String[] args) throws IOException, ClassNotFoundException {
25 FileOutputStream fos = new FileOutputStream("D:/1.dat");
26 ObjectOutputStream oos = new ObjectOutputStream(fos);
27 Book book = new Book("1", "Java", "A",20,10);
28 oos.writeObject(book);
29 oos.close();
30 FileInputStream fis = new FileInputStream("D:/1.dat");
31 ObjectInputStream ois = new ObjectInputStream(fis);
32 book = (Book)ois.readObject();
33 System.out.println(book.toString());
34 ois.close();
35 }
36 /* [Book: 1, Java, A,20,0] */
37
38 //example 2: 重载被序列化对象的writeObject和readObject方法
39 //1. 在被序列化的类中声明私有的writeObject和readObject方法,尽管是私有,
40 //序列化框架是仍然可以调用这两个方法的。
41 //2. 在这两个重载的方法中可以写出一些自定义的序列化和反序列化规则
42 //3. 在这两个方法的重载实现中,defaultWriteObject()和defaultReadObject()
43 //分别对应这框架中缺省的序列化写出对象和反序列化读入对象的逻辑,一般都会
44 //在这两个重载函数的开始处先执行这两个缺省方法,以完成缺省的序列化操作
45 class Employee implements Serializable {
46 private String name;
47 private double salary;
48 Employee(String name, double salary) {
49 this.name = name;
50 this.salary = salary;
51 }
52 String getName() {
53 return name;
54 }
55 double getSalary() {
56 return salary;
57 }
58 private void writeObject(ObjectOutputStream oos) throws IOException {
59 oos.defaultWriteObject();
60 System.out.println("Serializing Employee object\n");
61 }
62 private void readObject(ObjectInputStream ois) throws Exception {
63 ois.defaultReadObject();
64 salary += 100;
65 System.out.println("Deserializing Employee object");
66 }
67 }
68 public static void main(String[] args) throws IOException, ClassNotFoundException {
69 Employee e1 = new Employee("A", 45000.0);
70 System.out.println(e1.getName() + " " + e1.getSalary());
71 FileOutputStream fos = new FileOutputStream("D:/1.dat");
72 ObjectOutputStream oos = new ObjectOutputStream(fos);
73 oos.writeObject(e1);
74
75 FileInputStream fis = new FileInputStream("D:/1.dat");
76 ObjectInputStream ois = new ObjectInputStream(fis);
77 Employee e2 = (Employee)ois.readObject();
78 System.out.println(e2.getName() + " " + e2.getSalary());
79 }
80 /* 输出结果如下:
81 A 45000.0
82 Serializing Employee object
83 Deserializing Employee object
84 A 45100.0 */
85
86 //example 3: 如果被序列化的类继承自Externalizable接口,同时实现了
87 //该接口提供的两个接口方法readExternal和writeExternal,那么序列化
88 //和反序列化过程中的每一个细节均由这两个方法来进行控制。由于实现类
89 //中自行定义了序列化和反序列化的规则,因此不必像序列化框架那样,针
90 //对被序列化对象中的每个域字段进行反射然后再输出。因此效率会高于通
91 //用方式的序列化操作。通常在需要序列化大数据量的对象时,可以考虑采
92 //用该种方式
93 class Car implements Externalizable {
94 private int numTires;
95 private Engine e;
96 private String name;
97 public Car() {}
98 Car(String name, int numTires, Engine e) {
99 this.name = name;
100 this.numTires = numTires;
101 this.e = e;
102 }
103 int getNumTires() {
104 return numTires;
105 }
106 Engine getEngine() {
107 return e;
108 }
109 String getName() {
110 return name;
111 }
112 public void readExternal(ObjectInput in) throws IOException, ClassCastException {
113 System.out.println("READ-Car");
114 numTires = in.readInt();
115 name = in.readUTF();
116 try {
117 e = (Engine) in.readObject();
118 } catch (ClassNotFoundException e) {
119 }
120 }
121 public void writeExternal(ObjectOutput out) throws IOException {
122 System.out.println("WRITE-Car");
123 out.writeInt(numTires);
124 out.writeUTF(name);
125 out.writeObject(e);
126 }
127 }
128 class Engine implements Externalizable {
129 private int numCylinders;
130 public Engine() {
131 }
132 Engine(int numCylinders) {
133 this.numCylinders = numCylinders;
134 }
135 int getNumCylinders() {
136 return numCylinders;
137 }
138 public void readExternal(ObjectInput in) throws IOException, ClassCastException {
139 System.out.println("READ-Engine");
140 numCylinders = in.readInt();
141 }
142 public void writeExternal(ObjectOutput out) throws IOException {
143 System.out.println("WRITE-Engine");
144 out.writeInt(numCylinders);
145 }
146 }
147 public static void main(String[] args) throws IOException, ClassNotFoundException {
148 Car c1 = new Car("Some car", 4, new Engine(6));
149 ObjectOutputStream oos = null;
150 FileOutputStream fos = new FileOutputStream("D:/1.dat");
151 oos = new ObjectOutputStream(fos);
152 oos.writeObject(c1);
153 ObjectInputStream ois = null;
154 FileInputStream fis = new FileInputStream("D:/1.dat");
155 ois = new ObjectInputStream(fis);
156 Car c2 = (Car) ois.readObject();
157 System.out.println("Number of tires = " + c2.getNumTires());
158 System.out.println("Number of cylinders = " + c2.getEngine().getNumCylinders());
159 System.out.println("Name = " + c2.getName());
160 }
161 /* 输出结果如下:
162 WRITE-Car
163 WRITE-Engine
164 READ-Car
165 READ-Engine
166 Number of tires = 4
167 Number of cylinders = 6
168 Name = Some car
169 */