File类
package thinking.in.java.chapter10;
/**
* File 类有一个欺骗性的名字——通常会认为它对付的是一个文件,但实情并非如此。它既代表一个特定文件
* 的名字,也代表目录内一系列文件的名字。若代表一个文件集,便可用list()方法查询这个集,返回的是一
* 个字串数组。之所以要返回一个数组,而非某个灵活的集合类,是因为元素的数量是固定的。而且若想得到
* 一个不同的目录列表,只需创建一个不同的File 对象即可。事实上,“FilePath”(文件路径)似乎是一个
* 更好的名字。本节将向大家完整地例示如何使用这个类,其中包括相关的 FilenameFilter(文件名过滤器)
* 接口。
*/
/**
* 10.4.1 目录列表器
* 现在假设我们想观看一个目录列表。可用两种方式列出File 对象。若在不含自变量(参数)的情况下调用
* list(),会获得 File 对象包含的一个完整列表。然而,若想对这个列表进行某些限制,就需要使用一个“目
* 录过滤器”,该类的作用是指出应如何选择File 对象来完成显示。
*/
//: DirList.java
// Displays directory listing
import java.io.*;
public class DirList {
public static void main(String[] args) {
try {
File path = new File(".");
String[] list;
if(args.length == 0)
list = path.list();
else
list = path.list(new DirFilter(args[0]));
for(int i = 0; i < list.length; i++)
System.out.println(list[i]);
} catch(Exception e) {
e.printStackTrace();
}
}
}
class DirFilter implements FilenameFilter {
String afn;
DirFilter(String afn) { this.afn = afn; }
public boolean accept(File dir, String name) {
// Strip path information:
String f = new File(name).getName();
return f.indexOf(afn) != -1;
}
} ///:~
output result:
.git
.gitignore
.idea
.mvn
doc
mvnw
mvnw.cmd
out
pom.xml
readinglist.iml
README.en.md
README.md
src
target
Process finished with exit code 0
package thinking.in.java.chapter10;
/**
* 下例用一个匿名内部类(已在第7 章讲述)来重写显得非常理想。首先创建了一个filter()方法,它返回指
* 向FilenameFilter 的一个句柄:
*/
//: DirList2.java
// Uses Java 1.1 anonymous inner classes
import java.io.*;
public class DirList2 {
public static FilenameFilter
filter(final String afn) {
// Creation of anonymous inner class:
return new FilenameFilter() {
String fn = afn;
public boolean accept(File dir, String n) {
// Strip path information:
String f = new File(n).getName();
return f.indexOf(fn) != -1;
}
}; // End of anonymous inner class
}
public static void main(String[] args) {
try {
File path = new File(".");
String[] list;
if(args.length == 0)
list = path.list();
else
list = path.list(filter(args[0]));
for(int i = 0; i < list.length; i++)
System.out.println(list[i]);
} catch(Exception e) {
e.printStackTrace();
}
}
} ///:~
package thinking.in.java.chapter10;
//: DirList3.java
// Building the anonymous inner class "in-place"
import java.io.*;
public class DirList3 {
public static void main(final String[] args) {
try {
File path = new File(".");
String[] list;
if(args.length == 0)
list = path.list();
else
list = path.list(
new FilenameFilter() {
public boolean
accept(File dir, String n) {
String f = new File(n).getName();
return f.indexOf(args[0]) != -1;
}
});
for(int i = 0; i < list.length; i++)
System.out.println(list[i]);
} catch(Exception e) {
e.printStackTrace();
}
}
} ///:~
package thinking.in.java.chapter10;
//: SortedDirList.java
// Displays sorted directory listing
import thinking.in.java.chapter8.StrSortVector;
import java.io.*;
public class SortedDirList {
private File path;
private String[] list;
public SortedDirList(final String afn) {
path = new File(".");
if(afn == null)
list = path.list();
else
list = path.list(
new FilenameFilter() {
public boolean
accept(File dir, String n) {
String f = new File(n).getName();
return f.indexOf(afn) != -1;
}
});
sort();
}
void print() {
for(int i = 0; i < list.length; i++)
System.out.println(list[i]);
}
private void sort() {
StrSortVector sv = new StrSortVector();
for(int i = 0; i < list.length; i++)
sv.addElement(list[i]);
// The first time an element is pulled from
// the StrSortVector the list is sorted:
for(int i = 0; i < list.length; i++)
list[i] = sv.elementAt(i);
}
// Test it:
public static void main(String[] args) {
SortedDirList sd;
if(args.length == 0)
sd = new SortedDirList(null);
else
sd = new SortedDirList(args[0]);
sd.print();
}
} ///:~
//这里进行了另外少许改进。不再是将path(路径)和 list(列表)创建为main()的本地变量,它们变成了
//类的成员,使它们的值能在对象“生存”期间方便地访问。事实上,main()现在只是对类进行测试的一种方
//式。大家可以看到,一旦列表创建完毕,类的构建器就会自动开始对列表进行排序。
//这种排序不要求区分大小写,所以最终不会得到一组全部单词都以大写字母开头的列表,跟着是全部以小写
//字母开头的列表。然而,我们注意到在以相同字母开头的一组文件名中,大写字母是排在前面的——这对标
//准的排序来说仍是一种不合格的行为。Java 1.2 已成功解决了这个问题。
Usage:MakeDirectories path1 ...
Creates each path
Usage:MakeDirectories -d path1 ...
Deletes each path
Usage:MakeDirectories -r path1 path2
Renames from path1 to path2
Process finished with exit code 1
IO 流的典型应用
package thinking.in.java.chapter10;
//: IOStreamDemo.java
// Typical IO Stream Configurations
import java.io.*;
//import com.bruceeckel.tools.*;
public class IOStreamDemo {
public static void main(String[] args) {
try {
// 1. Buffered input file
DataInputStream in =
new DataInputStream(
new BufferedInputStream(
new FileInputStream(args[0])));
String s, s2 = new String();
while((s = in.readLine())!= null)
s2 += s + "\n";
in.close();
// 2. Input from memory
StringBufferInputStream in2 =
new StringBufferInputStream(s2);
int c;
while((c = in2.read()) != -1)
System.out.print((char)c);
// 3. Formatted memory input
try {
DataInputStream in3 =
new DataInputStream(
new StringBufferInputStream(s2));
while(true)
System.out.print((char)in3.readByte());
} catch(EOFException e) {
System.out.println(
"End of stream encountered");
}
// 4. Line numbering & file output
try {
LineNumberInputStream li =
new LineNumberInputStream(
new StringBufferInputStream(s2));
DataInputStream in4 =
new DataInputStream(li);
PrintStream out1 =
new PrintStream(
new BufferedOutputStream(
new FileOutputStream(
"IODemo.out")));
while((s = in4.readLine()) != null )
out1.println(
"Line " + li.getLineNumber() + s);
out1.close(); // finalize() not reliable!
} catch(EOFException e) {
System.out.println(
"End of stream encountered");
}
// 5. Storing & recovering data
try {
DataOutputStream out2 =
new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream("Data.txt")));
out2.writeBytes(
"Here's the value of pi: \n");
out2.writeDouble(3.14159);
out2.close();
DataInputStream in5 =
new DataInputStream(
new BufferedInputStream(
new FileInputStream("Data.txt")));
System.out.println(in5.readLine());
System.out.println(in5.readDouble());
} catch(EOFException e) {
System.out.println(
"End of stream encountered");
}
// 6. Reading/writing random access files
RandomAccessFile rf =
new RandomAccessFile("rtest.dat", "rw");
for(int i = 0; i < 10; i++)
rf.writeDouble(i*1.414);
rf.close();
rf =
new RandomAccessFile("rtest.dat", "rw");
rf.seek(5*8);
rf.writeDouble(47.0001);
rf.close();
rf =
new RandomAccessFile("rtest.dat", "r");
for(int i = 0; i < 10; i++)
System.out.println(
"Value " + i + ": " +
rf.readDouble());
rf.close();
// 7. File input shorthand
InFile in6 = new InFile(args[0]);
String s3 = new String();
System.out.println(
"First line in file: " +
in6.readLine());
in6.close();
// 8. Formatted file output shorthand
PrintFile out3 = new PrintFile("Data2.txt");
out3.print("Test of PrintFile");
out3.close();
// 9. Data file output shorthand
OutFile out4 = new OutFile("Data3.txt");
out4.writeBytes("Test of outDataFile\n\r");
out4.writeChars("Test of outDataFile\n\r");
out4.close();
} catch(FileNotFoundException e) {
System.out.println(
"File Not Found:" + args[0]);
} catch(IOException e) {
System.out.println("IO Exception");
}
}
} ///:~
package thinking.in.java.chapter10;
/**
* 3. 格式化内存输入
* StringBufferInputStream 的接口是有限的,所以通常需要将其封装到一个DataInputStream 内,从而增强
* 它的能力。然而,若选择用readByte()每次读出一个字符,那么所有值都是有效的,所以不可再用返回值来
* 侦测何时结束输入。相反,可用available()方法判断有多少字符可用。下面这个例子展示了如何从文件中
* 一次读出一个字符
*/
//: TestEOF.java
// Testing for the end of file while reading
// a byte at a time.
import java.io.*;
public class TestEOF {
public static void main(String[] args) {
try {
DataInputStream in =
new DataInputStream(
new BufferedInputStream(
new FileInputStream("src/main/java/thinking/in/java/chapter10/TestEOF.java")));
while(in.available() != 0)
System.out.print((char)in.readByte());
} catch (IOException e) {
System.err.println("IOException");
}
}
} ///:~
package thinking.in.java.chapter10;
/**
* 3. ₩ᅠᄐ¥ᄐマ¥フヨ¥ニナ¥ᆳリ│ᄒモ¥ナᆬ
* StringBufferInputStream レト₩ホᆬ¥マᆪ₩リᆵ₩ワノ←ルミレトᄐフ₩ノタ¦ᄏᆬ←タレ¥ᄌᄌ←ワタ│ᆭチ¥ᄚニ¥ナᄊ¥ᄚチ│ᆪナ¥ネᄚ¦ᄌタ¦ᄌᆰDataInputStream ¥ニナᄐフ¦ᄏホ│タフ¥ᄁ゙¥ᄐᄎ
* ¥ᆴテレト│テᄑ¥ハロ ̄タツトᄊ│タフᄐフ│ヒᆬ←タノ₩ヒᄅヤᄄreadByte()₩ᆵマ₩ᆲᄀ│ᆵᄏ¥ヌᄎ¦ᄌタ¦ᄌᆰ¥ᆳラᆲᆭᄐフ←ツᆪ¦ᄍネ₩ノタ₩ワノ¥タᄐ←テᄑ₩リᆵ₩ワノ₩ユネレトᄐフ₩ノタ¦ᄏᆬ¦ᄌヘ¥マᆵ¥ニヘヤᄄ│ヤ¥ロ゙¥タᄐ₩ンᆬ
* ¦ᄒᆭ₩ᄉヒ¦ᄑユ₩ラᄊᄏモ₩ン゚│ᄒモ¥ナᆬ ̄タツロᄌ¥マヘᄐフ¥マᆵヤᄄavailable()₩ヨᄍ₩ᄈユ¥ネᄂ₩ヨᆳ₩ワノ¥ᄂレ¥ᄚム¥ᆳラᆲᆭ¥マᆵヤᄄ ̄タツ¦ᄌヒ←ンᄁ│ル¦ᄌᆰ¦ᄒヒ¥ᆳミ¥ᄆユᄂᄎ¦ᄎニ¥ᆭツ¦ᄑユ¦ᄏホ₩ヨヌ¦ᄏᄊ¦ᄌᆳ
* ¦ᄌタ₩ᆲᄀ│ᆵᄏ¥ヌᄎ¦ᄌタ¦ᄌᆰ¥ᆳラᆲᆭ
*/
//: TestEOF.java
// Testing for the end of file while reading
// a byte at a time.
import java.io.*;
public class TestEOF {
public static void main(String[] args) {
try {
DataInputStream in =
new DataInputStream(
new BufferedInputStream(
new FileInputStream("src/main/java/thinking/in/java/chapter10/TestEOF.java")));
while(in.available() != 0)
System.out.print((char)in.readByte());
} catch (IOException e) {
System.err.println("IOException");
}
}
} ///:~
Process finished with exit code 0
/**
* 7. 快速文件输入
* 若想创建一个对象,用它从一个缓冲的DataInputStream 中读取一个文件,可将这个过程封装到一个名为
* InFile 的类内。如下所示:
*/
import java.io.*;
public class InFile extends DataInputStream {
public InFile(String filename)
throws FileNotFoundException {
super(
new BufferedInputStream(
new FileInputStream(filename)));
}
public InFile(File file)
throws FileNotFoundException {
this(file.getPath());
}
} ///:~
package thinking.in.java.chapter10;
import java.io.*;
/**
* 8. 快速输出格式化文件
* 亦可用同类型的方法创建一个 PrintStream,令其写入一个缓冲文件。下面是对com.bruceeckel.tools 的扩
* 展:
*/
public class PrintFile extends PrintStream {
public PrintFile(String filename)
throws IOException {
super(
new BufferedOutputStream(
new FileOutputStream(filename)));
}
public PrintFile(File file)
throws IOException {
this(file.getPath());
}
} ///:~
package thinking.in.java.chapter10;
import java.io.*;
/**
* 9. 快速输出数据文件
* 最后,利用类似的快捷方式可创建一个缓冲输出文件,用它保存数据(与由人观看的数据格式相反):
*/
public class OutFile extends DataOutputStream {
public OutFile(String filename)
throws IOException {
super(
new BufferedOutputStream(
new FileOutputStream(filename)));
}
public OutFile(File file)
throws IOException {
this(file.getPath());
}
} ///:~
package thinking.in.java.chapter10;
//: Echo.java
// How to read from standard input
import java.io.*;
/**
* 10.5.4 从标准输入中读取数据
* 以Unix 首先倡导的“标准输入”、“标准输出”以及“标准错误输出”概念为基础,Java 提供了相应的
* System.in,System.out 以及System.err。贯这一整本书,大家都会接触到如何用 System.out 进行标准输
* 出,它已预封装成一个 PrintStream 对象。System.err 同样是一个 PrintStream,但System.in 是一个原始
* 的InputStream,未进行任何封装处理。这意味着尽管能直接使用 System.out 和System.err,但必须事先封
* 装System.in,否则不能从中读取数据。
* 典型情况下,我们希望用readLine()每次读取一行输入信息,所以需要将System.in 封装到一个
* DataInputStream 中。这是 Java 1.0 进行行输入时采取的“老”办法。在本章稍后,大家还会看到 Java 1.1
* 的解决方案。下面是个简单的例子,作用是回应我们键入的每一行内容:
*/
public class Echo {
public static void main(String[] args) {
DataInputStream in =
new DataInputStream(
new BufferedInputStream(System.in));
String s;
/**
* 之所以要使用try 块,是由于 readLine()可能“掷”出一个 IOException。注意同其他大多数流一样,也应
* 对System.in 进行缓冲。
* 由于在每个程序中都要将System.in 封装到一个 DataInputStream 内,所以显得有点不方便。但采用这种设
* 计方案,可以获得最大的灵活性。
*/
try {
while((s = in.readLine()).length() != 0)
System.out.println(s);
// An empty line terminates the program
} catch(IOException e) {
e.printStackTrace();
}
}
} ///:~
package thinking.in.java.chapter10;
//: SortedWordCount.java
// Counts words in a file, outputs
// results in sorted form.
import thinking.in.java.chapter8.StrSortVector;
import java.io.*;
import java.util.*;
/**
* 下面是一个简单的程序,用于计算各个单词在文本文件中重复出现的次数:
*/
class Counter {
private int i = 1;
int read() { return i; }
void increment() { i++; }
}
public class SortedWordCount {
private FileInputStream file;
private StreamTokenizer st;
private Hashtable counts = new Hashtable();
SortedWordCount(String filename)
throws FileNotFoundException {
try {
file = new FileInputStream(filename);
st = new StreamTokenizer(file);
st.ordinaryChar('.');
st.ordinaryChar('-');
} catch(FileNotFoundException e) {
System.out.println(
"Could not open " + filename);
throw e;
}
}
void cleanup() {
try {
file.close();
} catch(IOException e) {
System.out.println(
"file.close() unsuccessful");
}
}
void countWords() {
try {
while(st.nextToken() !=
StreamTokenizer.TT_EOF) {
String s;
switch(st.ttype) {
case StreamTokenizer.TT_EOL:
s = new String("EOL");
break;
case StreamTokenizer.TT_NUMBER:
s = Double.toString(st.nval);
break;
case StreamTokenizer.TT_WORD:
s = st.sval; // Already a String
break;
default: // single character in ttype
s = String.valueOf((char)st.ttype);
}
if(counts.containsKey(s))
((Counter)counts.get(s)).increment();
else
counts.put(s, new Counter());
}
} catch(IOException e) {
System.out.println(
"st.nextToken() unsuccessful");
}
}
Enumeration values() {
return counts.elements();
}
Enumeration keys() { return counts.keys(); }
Counter getCounter(String s) {
return (Counter)counts.get(s);
}
Enumeration sortedKeys() {
Enumeration e = counts.keys();
StrSortVector sv = new StrSortVector();
while(e.hasMoreElements())
sv.addElement((String)e.nextElement());
// This call forces a sort:
return sv.elements();
}
public static void main(String[] args) {
try {
SortedWordCount wc =
new SortedWordCount(args[0]);
wc.countWords();
Enumeration keys = wc.sortedKeys();
while(keys.hasMoreElements()) {
String key = (String)keys.nextElement();
System.out.println(key + ": "
+ wc.getCounter(key).read());
}
wc.cleanup();
} catch(Exception e) {
e.printStackTrace();
}
}
} ///:~
package thinking.in.java.chapter8;
//: StrSortVector.java
// Automatically sorted Vector that
// accepts and produces only Strings
import java.util.*;
public class StrSortVector {
private SortVector v = new SortVector(
// Anonymous inner class:
new Compare() {
public boolean
lessThan(Object l, Object r) {
return
((String)l).toLowerCase().compareTo(
((String)r).toLowerCase()) < 0;
}
public boolean
lessThanOrEqual(Object l, Object r) {
return
((String)l).toLowerCase().compareTo(
((String)r).toLowerCase()) <= 0;
}
}
);
private boolean sorted = false;
public void addElement(String s) {
v.addElement(s);
sorted = false;
}
public String elementAt(int index) {
if(!sorted) {
v.sort();
sorted = true;
}
return (String)v.elementAt(index);
}
public Enumeration elements() {
if(!sorted) {
v.sort();
sorted = true;
}
return v.elements();
}
// Test it:
public static void main(String[] args) {
StrSortVector sv = new StrSortVector();
sv.addElement("d");
sv.addElement("A");
sv.addElement("C");
sv.addElement("c");
sv.addElement("b");
sv.addElement("B");
sv.addElement("D");
sv.addElement("a");
Enumeration e = sv.elements();
while(e.hasMoreElements())
System.out.println(e.nextElement());
}
} ///:~
package thinking.in.java.chapter10;
//: AnalyzeSentence.java
// Look for particular sequences
// within sentences.
import java.util.*;
public class AnalyzeSentence {
public static void main(String[] args) {
analyze("I am happy about this");
analyze("I am not happy about this");
analyze("I am not! I am happy");
analyze("I am sad about this");
analyze("I am not sad about this");
analyze("I am not! I am sad");
analyze("Are you happy about this?");
analyze("Are you sad about this?");
analyze("It's you! I am happy");
analyze("It's you! I am sad");
}
static StringTokenizer st;
static void analyze(String s) {
prt("\nnew sentence >> " + s);
boolean sad = false;
st = new StringTokenizer(s);
while (st.hasMoreTokens()) {
String token = next();
// Look until you find one of the
// two starting tokens:
if(!token.equals("I") &&
!token.equals("Are"))
continue; // Top of while loop
if(token.equals("I")) {
String tk2 = next();
if(!tk2.equals("am")) // Must be after I
break; // Out of while loop
else {
String tk3 = next();
if(tk3.equals("sad")) {
sad = true;
break; // Out of while loop
}
if (tk3.equals("not")) {
String tk4 = next();
if(tk4.equals("sad"))
break; // Leave sad false
if(tk4.equals("happy")) {
sad = true;
break;
}
}
}
}
if(token.equals("Are")) {
String tk2 = next();
if(!tk2.equals("you"))
break; // Must be after Are
String tk3 = next();
if(tk3.equals("sad"))
sad = true;
break; // Out of while loop
}
}
if(sad) prt("Sad detected");
}
static String next() {
if(st.hasMoreTokens()) {
String s = st.nextToken();
prt(s);
return s;
}
else
return "";
}
static void prt(String s) {
System.out.println(s);
}
} ///:~