输入、输出流及文件管理

文件及目录

File类

  • File类提供了若干处理文件、目录和获取它们基本信息的方法;
  • java中目录也是文件(File),java中没有Directory类;
1
2
3
4
5
6
7
//File类的构造方法有三个
//1
File(String pathname);
//2
File(String parent,String child);
//3
File(File parent,String child);

文件类例子

在Java中,将目录也当作文件处理

1
2
3
4
5
6
7
File f;
f=new File("Test.java");
//
f=new File("E:\\ex\\","Test.java");
//
File path=new File("E:\\ex\\");
File f=new File(path,"Test.java");

File类方法介绍

File类方法介绍

File类的作用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
//创建目录
//ch08.UseFile.main()
//递归列目录
//ch08.UseFile.listDir()
//递归删目录
//ch08.UseFile.deleteDir()
//ch08.UseFile.java
package ch08;
import java.io.File;
import java.io.IOException;
import java.util.Date;
public class UseFile {
public static void main(String args[]) throws Exception {
// 创建目录
File dir1 = new File("D:/dir1");
if (!dir1.exists()) {
dir1.mkdir();
}
// 在某个目录下 创建目录
File dir2 = new File(dir1, "dir2");
if (!dir2.exists()) {
dir2.mkdirs();
}
// 在某个目录下 创建多层目录
File dir4 = new File(dir1, "dir3\\dir4");
if (!dir4.exists())
dir4.mkdirs();
// 在某个目录下 创建文件
File file = new File(dir2, "test.txt");
if (!file.exists()) {
file.createNewFile();
}
file = new File("D:/dir1/mytest.txt");
if (!file.exists()) {
file.createNewFile();
}
listDir(dir1);
deleteDir(dir1);
}
/**
* 察看目录信息
*/
public static void listDir(File dir) throws IOException {
if (dir.isFile()) {
System.out.println(
"文件:" + dir.getCanonicalPath() + " 修改日期:" + new Date(dir.lastModified()) + " 大小:" + dir.length());
return;
}
File[] lists = dir.listFiles();
// 打印当前目录下包含的所有子目录和文件的详细信息
for (int i = 0; i < lists.length; i++) {
File f = lists[i];
// 如果为目录,就递归调用listDir()方法
System.out.println("目录:" + f.getCanonicalPath() + " 修改日期:" + new Date(f.lastModified()));
listDir(f);
}
}
/** 删除目录或文件,如果参数file代表目录,会删除当前目录以及目录下的所有内容 */
public static void deleteDir(File file) {
// 如果file代表文件,就删除该文件
if (file.isFile()) {
file.delete();
return;
}
// 如果file代表目录,先删除目录下的所有子目录和文件
File[] lists = file.listFiles();
for (int i = 0; i < lists.length; i++) {
deleteDir(lists[i]); // 递归删除当前目录下的所有子目录和文件
}
// 最后删除当前目录
file.delete();
}
}
//递归列目录
//ch08.ListAllFiles.java
package ch08;
import java.io.*;
/**
* 使用递归的方式,列出一个目录下面所有的子目录和文件
*/
public class ListAllFiles {
public static void main(String[] args) {
ListFiles(new File("D:\\course\\course\\code_demo\\src\\"));
}

public static void ListFiles(File dir) {
if (!dir.exists() || !dir.isDirectory()) {
return;
}

String[] files = dir.list();
for (int i = 0; i < files.length; i++) {
File file = new File(dir, files[i]);
if (file.isFile()) {
System.out.println(dir + "\\" + file.getName() + "\t size=" + file.length());
} else {
System.out.println(dir + "\\" + file.getName() + "\t<dir>");

ListFiles(file); // 对于子目录,进行递归调用
}
}
}
}

输入流/输出流

定义

  • 大部分程序都需要输入/输出处理,比如从键盘读取数据、向屏幕中输出数据、从文件中读或者向文件中写数据、在一个网络连接上进行读写操作等。在Java中,把这些不同类型的输入、输出源抽象为流Stream;
  • 按流的方向,可分为输入流与输出流。

字节流与字符流

字节流(byte) 字符流(char)
输入 InputStream Reader
输出 OutputStream Writer

InputStream类

InputStream类最重要的方法是读数据的read()方法。read()方法功能是逐字节地以二进制的原始方式读取数据

1
2
3
4
5
6
7
//read()读取数据有三种形式
//1
public int read();
//2
public int read(byte b[]);
//3
public int read(byte[] b,int off,int len);

OutputStream类

OutputStream类的重要方法是write(),它的功能是将字节写入流中,write()方法有三种形式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//1
public void write(int b);
//将参数b的低位字节写入到输出流
//2
public void write(byte b[]);
//将字节数组b[]中的全部字节顺序写入到输出流
//3
public void write(byte[] b,int off,int len);
//将字节数组b[]中从off开始的len个字节写入到流中
//Others functions
public void flush();
//强制输出缓冲区中的数据
public void close();
//关闭流

Reader类

  • Reader类与InputStream类相似,都是输入流,但差别在于Reader类读取的字符(char),而不是字节;
  • Reader的重要方法是read(),共有三种形式:
1
2
3
public int read();
public int read(char b[]);
public int read(char[] b,int off,int len);

Writer类

Writer类与OutputStream类相似,都是输出流,但差别在于Writer类写入的字符(char),而不是字节

1
2
3
4
5
6
7
8
9
10
11
12
public void write(int b);
//将参数b的低两字节写入到输出流
public void write(char b[]);
//将字符数组b[]中的全部字节顺序写入到输出流
public void write(char[] b,int off,int len);
//将字节数组b[]中从off开始的len个字符写入到流中
public void write(String s);
//将字符串写入流中
public void write(String s,int off,int len);
//将字符串中从off开始的len个字符写入到流中
public void flush();//刷新流
public void close();//关闭流

节点流和处理流

按照流是否直接与特定的地方(如磁盘、内存、设备等)相连,分为节点流与处理流两类

节点流(Node Stream)

可以从或向一个特定的地方(节点)读写数据。如文件流FileReader

处理流(Processing Stream)

是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读、写功能。处理流又称为过滤流,如缓冲处理流BufferedReader

节点流与处理流的关系

节点流与处理流的关系

  • 其关系如上图所示;
  • 节点流直接与节点(如文件)相连,而处理流对节点流或其他处理流进一步进行处理(如缓冲、组装成对象等等)。
1
2
3
4
5
6
//处理流的构造方法总是要带一个其他的流对象作为参数
//For example:
BufferedReader in=new BufferedReader(new FileReader(file));
BufferedReader in2=new BufferedReader(
new InputstReamreader(
new FileInputStream(file)));

一个流对象经过其他流的多次包装,称为流的链接

流的链接

常用的节点流

节点类型 字节流 字符流
File
文件
FileInputStream
FileOutputStream
FileReader
FileWriter
Memory Array
内存数组
ByteArrayInputStream
ByteArrayOutputStream
CharArrayReader
CharArrayWriter
Memory String StringReader
StringWriter
Pipe
管道
PipedInputStream
PipedOutputStream
PipedReader
PipedWriter

常用的处理流

处理类型 字节流 字符流
Buffering
缓冲
BufferedInputStream
BufferedOutputStream
BufferedReader
BufferedWriter
Filtering
过滤
FilterInputStream
FilterOutputStream
FilterReader
FilterWriter
Converting between bytes and character
字节流转为字符流
InputStreamReader
OutputStreamWriter
Object Serialization
对象序列化
ObjectInputStream
ObjectOutputStream
Data conversion
基本数据类型转化
DataInputStream
DataOutputStream
Counting
行号处理
LineNumberInputStream LineNumberReader
Peeking ahead
可回退流
PushbackInputStream PushbackReader
Pinting
可显示处理
PrintStream PrintWriter

输入输出流例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
//ch08.ReadWriteFileByteDemo.java
//InputStream/OutputStream
package ch08;
import java.io.Closeable;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* 本例子演示了如何用面向byte的方式 读取、写入文件
*/
public class ReadWriteFileByteDemo {
public static int CHUNK_SIZE = 4096;
public ReadWriteFileByteDemo() {
// TODO Auto-generated constructor stub
}
public static void main(String[] args) {
// TODO Auto-generated method stub
try { copyFile("D:\\course\\course\\code_demo\\src\\ch08\\src.txt","D:\\course\\course\\code_demo\\src\\ch08\\target.txt");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 复制IO流
* @throws IOException
*/
public static void copyIO(InputStream in, OutputStream out)
throws IOException {
byte[] buf = new byte[CHUNK_SIZE];
/**
* 从输入流读取内容并写入到另外一个流的典型方法
*/
int len = in.read(buf);
while (len != -1) {
out.write(buf, 0, len);
len = in.read(buf);
}
}
/**
* 复制文件
* @throws IOException
*/
public static void copyFile(String fsrc, String fdest) throws IOException {
InputStream in = null;
OutputStream out = null;
try {
in = new FileInputStream(fsrc);
out = new FileOutputStream(fdest, true);
copyIO(in, out);
} finally {
close(in);
close(out);
}
}
/**
* 关闭一个输入 输出流
*/
public static void close(Closeable inout) {
if (inout != null) {
try {
inout.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
//ch08.ReadWriteFileCharDemo.java
//Reader/Writer
package ch08;
import java.io.Closeable;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.io.OutputStream;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
/**
* 本例子演示了如何使用char的方式 读取、写入文件
*/
public class ReadWriteFileCharDemo {
public static int CHUNK_SIZE = 4096;
public ReadWriteFileCharDemo() {
// TODO Auto-generated constructor stub
}
public static void main(String[] args) {
String s = "";
try {
s = readFile("D:\\course\\course\\code_demo\\src\\ch08\\src.txt");
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(s);
try {
writeFile("D:\\course\\course\\code_demo\\src\\ch08\\target.txt", s);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 注意readFile和readFile2等效
* @throws IOException
*/
public static String readFile(String fsrc) throws IOException {
//这句话是否可以写成Reader reader ;为什么?
Reader reader = null;
try {
reader = new FileReader(fsrc);
StringBuffer buf = new StringBuffer();
char[] chars = new char[CHUNK_SIZE];
int readed = reader.read(chars);
// 从一个流里面读取内容的经典写法
while (readed != -1) {
// 文件是size不能被CHUNK_SIZE整除,所以要记录每次读到的长度readed
// 写入到buf的时候,不是用的 buf.append(chars);
// 而是用buf.append(chars, 0, readed);
buf.append(chars, 0, readed);
readed = reader.read(chars);
}
return buf.toString();
} finally {
//reader!=null的判断是否可以取消,为什么?
if (reader != null) {
reader.close();
}
}
}
/**
* 从一个文件中读取字符串
* @throws IOException
*/
public static String readFile2(String fsrc) throws IOException {
try (Reader reader = new FileReader(fsrc);) {
StringBuffer buf = new StringBuffer();
char[] chars = new char[CHUNK_SIZE];
int readed = reader.read(chars);
// 从一个流里面读取内容的经典写法
while (readed != -1) {
buf.append(chars, 0, readed);
readed = reader.read(chars);
}
return buf.toString();
}
}
/**
* 把字符串写到文件中
* @throws IOException
*/
public static void writeFile(String fileName, String content) throws IOException {
try (OutputStream out = new FileOutputStream(fileName, false)) {
out.write(content.getBytes());
out.flush();
}
}
/**
* 关闭输入输入流
*/
public static void close(Closeable inout) {
if (inout != null) {
try {
inout.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

再谈节点流和处理流

再谈节点流和处理流

使用处理流的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
//ch08.ReadFileByProcessingStream.java
package ch08;
import java.io.Closeable;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.io.OutputStream;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
/**
* 本例子演示了如何使用char的方式 读取、写入文件
*/
public class ReadFileByProcessingStream {
public static int CHUNK_SIZE = 4096;
public ReadFileByProcessingStream() {
// TODO Auto-generated constructor stub
}
public static void main(String[] args) {
try {
List<String> lines = readLines("D:\\course\\course\\code_demo\\src\\ch08\\XiaoHe.ini");
for (String line : lines) {
System.out.println(line);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 从一个文本文件中,一次读取一行,放到list中
* @throws IOException
*/
public static List<String> readLines(String fsrc) throws IOException {
try (Reader reader = new FileReader(fsrc);
//LineNumberReader 必须在其他流基础上构建
LineNumberReader lineReader = new LineNumberReader(reader);) {
String line = "";
List<String> lines = new ArrayList<String>();
while (line != null) {
lines.add(line);
//每次读取一行
line = lineReader.readLine();
}
return lines;
}
}
}

System中的标准输入和标准输出

  • System.out提供向"标准输出"写出数据的功能

    System.out为PrintStream类型;

  • System.in提供从"标准输入"读入数据的功能

    System.in为InputStream类型;

  • System.err提供向"标准错误输出"写出数据的功能

    System.err为PrintStream类型。

向标准输出写出数据

System.out/System.err的println/print方法

  • println方法可将方法参数输出并换行;
  • print方法将方法参数输出但不换行;
  • print和prinln方法针对多数数据类型进行了重写(boolean, char, int, long, float, double, char[], Object, String);
  • print(Object)和println(Object)方法中调用了参数的toString()方法,再将生成的字符串输出。

从标准输入读取数据

为了使用方便,经常将System.in用各种处理流进行封装处理

1
2
3
4
//For example:
BufferedReader br=new BufferedReader(
new InputStreamReader(System.in));
br.readLine();

文件的随机访问RandomAccessFile类

RandomAccessFile

基于文本应用的几个问题

命令行参数

  • 在启动Java应用程序时可以一次性地向应用程序中传递0~多个参数——命令行参数;

  • 命令函参数使用格式:

    1
    java ClassName lisa "bily" "Mr Brown"
  • 命令行参数被系统以String数组的方式传递给应用程序中的main方法,由参数args接收

    1
    public static void main(String[] args){}
1
2
3
4
5
6
7
8
9
10
11
12
13
//ch08.TestCommandLine
package ch08;
/**
* 演示了命令行的作用
*/
public class TestCommandLine {
public static void main(String[] args) {
for (int i = 0; i < args.length; i++) {
// 运行时,使用java TestCommandLine lisa "bily" "Mr Brown"
System.out.println("args[" + i + "] = " + args[i]);
}
}
}

命令行参数用法举例

命令行参数用法举例

系统属性(System Properties)

  • 在Java中,系统属性起到替代环境变量的作用(环境变量是平台相关的);
  • 可使用System.getProperties()方法获得一个Properties类的对象,其中包含了所有可用的系统属性信息;
  • 可使用System.getProperties(String name)方法获得特定系统属性的属性值;
  • 在命令行运行Java程序时可使用-D选项添加新的系统属性。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//ch08.TestProperties.java
package ch08;
import java.util.Iterator;
import java.util.Properties;
/**
* 本例子演示了如何取得System.properties
*/
public class TestProperties {
public static void main(String[] args) {
Properties ps = System.getProperties();
Iterator<Object> it = ps.keySet().iterator();
while (it.hasNext()) {
String pName = (String) it.next();
String pValue = ps.getProperty(pName);
System.out.println(pName + "=" + pValue);
}
}
}

正则表达式

定义

正则表达式是文本处理中常用的工具,它实际上是用来匹配字符串的一种模式。在Java中有一个正则表达式引擎(在java.util.regex包中),可以用正则表达式来验证和处理文本字符

基本元素

基本元素

基本元素

基本元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
//ch08.RegExpDemo
package ch08;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 本例子演示了正则表达式的用法
*/
public class RegExpDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
findEmail( );
testTels();
splitContent();
}
public static void testTels( ) {
testTel("13820477575");
testTel("123456");
}
private static void testTel(String content) {
boolean match=content.matches("[0-9]{11}");
System.out.println(content +(match?" ":" 不")+"是合法的电话号码");
}
public static void findEmail( ) {
String content = "天外天技术支持:cs@tju.edu.cn 联系我们:1234567890@qq.com 地址:天津市南开区";
String telReg = "\\w+@\\w+.[\\w+]+";
Pattern telPattern = Pattern.compile(telReg);
Matcher m = telPattern.matcher(content);
while (m.find()) {
System.out.println(m.group(0));
}
}
public static void splitContent() {
String content=" 第一回 甄士隐梦幻识通灵 贾雨村风尘怀闺秀 ... 第二回 贾夫人仙逝扬州城 冷子兴演说荣国府 ... 第三回 托内兄如海酬训教 接外孙贾母惜孤女 ....";
String contents[] = content.split("第[一,二,三,四,五,六,七,八,九,十,零]{1,3}回 ");
for(String title:contents) {
System.out.println(title);
}
}
}

Points

  • try{}final{}中如果有impments Closable的对象要申请并关闭的时候,ch08.ReadWriteFileCharDemo中两种写法等效
    1. reader必须impments Closable;
    2. 必须在try{}里面申请。
1
2
//From ch08.ReadWriteFileCharDemo
//readFile & readFile2
  • 修改文本文件中内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import java.io.*;
public class FileTool{
//修改homeDir中的txt文件,包括子目录下的txt文件,将orgStr改为targetStr
public void replaceTxtFileContent(String homeDir,String orgStr,String targetStr) {
File file=new File(homeDir);
if(file.isDirectory()) {
for(String str:file.list()) {
if(str.endsWith(".txt")) {
String filename=homeDir+str+"/";
File temp=new File(filename);
try {
BufferedReader reader=new BufferedReader(new FileReader(filename));
String line=reader.readLine();
//不能直接对line进行修改,因为line是reader读出的数据,不能直接利用字符串修改
String newLine=line.replaceAll(orgStr, targetStr);
//需要新建一个字符串,将orgStr替换为targetStr
//新建文件输出流
FileOutputStream os=new FileOutputStream(temp);
OutputStreamWriter writer=new OutputStreamWriter(os,"UTF-8");
writer.append(newLine);//向缓冲区写入修改后的字符串
writer.close();//关闭writer后,会将缓冲区的数据写入目标文件
} catch (FileNotFoundException e) {
System.out.println(filename);
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
File temp=new File(homeDir+str+"/");
if(temp.isDirectory()) {
replaceTxtFileContent(homeDir+str+"/",orgStr,targetStr);
}
}
}
}
}
  • 查看文件大小
1
2
File file=new File(filePath);
long fileSize=file.length();

文章源码

文章源码 备用仓库