Java I/O 系列文章目录:
- Java I/O 流操作(一)System Properties Runtime 类
- Java I/O 流操作(二)字节流与缓冲流
- Java I/O 流操作(三)文件流、打印流、缓冲流、SequenceInputStream
- Java I/O 流操作(四)对象的序列化
本文涉及到的I/O类
- File
- Properties
- FileInputStream
- FileOutputStream
- PrintStream
- PrintWriter
- BufferedReader
- InputStreamReader
- SequenceInputStream
File文件操作
下面来看一下 File 类的构造函数:
私有构造函数:
- private File(String pathname, int prefixLength)
- private File(String child, File parent)
公有构造函数:
- public File(String pathname)
- public File(String parent, String child)
- public File(File parent, String child)
- public File(URI uri)
一个小的测试 Demo:
File file =new File("a.txt");
File file2 =new File("C:\\file\\test\\a.txt");
File d =new File("C:\\file\\test\\");
File file3 =new File(d, "a.txt");
File file4 =new File("C:\\file\\test\\","a.txt");//这和file3是一回事
System.out.println(file +"\r\n" + file2 + "\r\n" + file3 +"\r\n" + file4 + "\r\n");
控制台输出为:
a.txt
C:\file\test\a.txt
C:\file\test\a.txt
C:\file\test\a.txt
File file5 = new File("C:"+File.separator+"file"+File.separator+"test"+File.separator+"", "a.txt");
File 常用方法
- createNewFile: 在指定位置创建文件,如果文件不存在,则创建成功返回 true ,如果文件已经存在,则不创建,返回 false 这和输出流不同,输出流一旦实例化就会创建文件,文件不存在创建,存在则覆盖.
- mkdir:创建文件夹
- mkdirs:创建文件夹,包括父文件夹
- delete:根据抽象的路径名称删除文件,如果程序出现异常没有执行到该行代码,那么这个文件就不会被执行,有人会说放在 finally 执行,但是如果一个程序正在使用该文件,那么这个文件还是不能被删除.
- deleteOnExit:这个方法不会发生这种情况,因为该方法在虚拟机停终止,文件就会被删除.
- exists:表示抽象的路径名称所指示的文件或文件夹是否存在
- canExecute:应用程序能否执行抽象路径名称所指示的文件
- canRead:应用程序能否读取抽象路径名称所指示的文件
- canWrite:应用程序能否修改抽象路径名称所指示的文件
- isDirectory:抽象路径名称所指示的是不是文件夹
- isFile:抽象路径名称所指示的是不是文件
- isAbsolute:判断是否是绝对路径
- getAbsoluteFile:返回 File 对象的绝对路径,但是他把这个字符串封装成了 File 对象返回 这也是和 getAbsolutePath 的主要区别
- getAbsolutePath:返回 File 对象的绝对路径
- getPath:返回 File 对象的路径,如果File里的抽象路径名称是绝对路径,如果是相对路径,就返回相对路径
- getName:如果 File 对象里的抽象路径名称指定的是目录,那么返回的目录最后的文件夹名称,如果是文件,则返回文件的名称
- getParent:如果 File 对象里的抽象路径名称指定的是目录,那么返回的目录最后的文件夹的上一个文件夹的名称,如果是文件,则返回文件所在目录的名称,如果象路径名称指定的是相对路径,有可能返回 null,如: File file = new File("a.txt"); 那么该 file 的父目录就是 null.
- getParentFile:这和 getParent 的区别就是,这个方法把 getParent 方法的返回值封装成了 File 对象
- length:返回文件的大小
- renameTo(File dest):重命名
- listRoots:返回系统盘符的名称 如 C、D 盘等
- list:返回 File 目录下的所有文件 如果抽象的路径名称指定的是一个文件将会出现空指针异常;并且该目录一定要存在
- listFiles:这个方法和 list() 方法的区别是 list() 方法是返回一个个字符串的,而 listFiles 是返回一个个 File 对象.那么就可以通过 File 对象获取文件的信息了,所以 File[] listFiles() 方法更使用一些
- listFiles(FileFilter filter):根据过滤器,返回文件列表
File 常用方法 Demo 讲解
Demo1:isDirectory、isFile 方法
File file =new File("a.txt");
System.out.println("isDirectory:"+file.isDirectory()); // false
System.out.println("isFile:"+file.isFile()); // false
发现它既不是文件也不是目录,为什么会出现这样的情况呢?
原来用上面的两个方法判断时候,需要先判断该抽象的路径名称所指定的 file 和 directory 是否存在,存在才能进行判断.
File f =new File("C:\\test\\test.txt");
File f2 =new File("C:\\test\\testDemo.txt");
f.renameTo(f2);
如果盘符或者目录不同这就成了剪切了
Demo3 :listRoots、list 方法
// listRoots
for(File file: File.listRoots()){
System.out.println(file);
}
// 控制台输出:
C:\
D:\
E:\
F:\
G:\
// list
File file =new File("C:\\");
for (String name : file.list()) {
System.out.println(name);
}
输出结果为:C 盘目录下的所有文件和目录包含隐藏文件,但是不包含子文件夹里的文件
public static void method_1() {
final File file =new File("D:\\");
String[] names = file.list(new FilenameFilter() {
publicboolean accept(File dir, String name) {
return name.endsWith(".java");
}
});
for (String name : names)
System.out.println(name);
}
Demo5:listFiles、listFiles(FileFilter filter)
/*
File[] listFiles() 这个方法和 list() 方法的区别是 list() 方法是返回一个个字符串的,
而 listFiles() 是返回一个个 File 对象,那么就可以通过 File 对象获取文件的信息了,所以File[]listFiles() 方法更使用一些。
*/
File file =new File("C:\\");
for(File file2 : file.listFiles()){
System.out.println(file2.getName());
}
/*
listFiles() 同样也有自己的过滤功能.通过 listFiles(FileFilter filter) 方法可以实现.
通过普通的递归实现列出目录下的所有文件
*/
publicstatic void main(String[] args) {
File file =new File("E:\\MyeclipseWorkbenck\\shop");
method_1(file);
}
publicstatic void method_1(File file) {
System.out.println(file.getAbsolutePath());
File[] files = file.listFiles();
for (File file2 : files) {
if(file2.isDirectory()){
method_1(file2);
} else {
System.out.println(file2.getName());
}
}
}
Demo6:delete、deleteDir
/*
删除带目录的文件,如果直接使用 delete 方法,则不能删除成功,
因为 Java 删除文件的原理是这样的, 把最里面的文件删除,然后删除文件夹
*/
publicstatic void main(String[] args) {
File file =new File("D:\\java");
deleteDir(file);
}
publicstatic void deleteDir(File file){
File[] files = file.listFiles();
for(File file2 : files){
//如果是目录
if(file2.isDirectory()){
//则使用递归 调用本身
deleteDir(file2);
} else {
//不是目录就直接删除
file2.delete();
}
}
//然后删除空文件夹
file.delete();
}
Demo7 将 File 路径存入集合中(使用递归和IO操作)
public class JavaFileItem {
public static void main(String[] args) {
List<File> list =new ArrayList<File>();
saveJavaFilePath(new File("E:\\MyeclipseWorkbenck\\HeimaTest"), list);
writeFilePath(list,"javaItem.txt");
}
//则把java文件放在集合中
publicstatic void saveJavaFilePath(File dir, List<File> list) {
File[] files = dir.listFiles();
for (File file : files) {
if (file.isDirectory()) {
saveJavaFilePath(file, list);
}else {
//如果是java文件,则把该文件放在集合中
if (file.getAbsolutePath().endsWith(".java"))
list.add(file);
}
}
}
//把java的路径信息写入文件中
publicstatic void writeFilePath(List<File> files, String targetFile) {
BufferedWriter buffw =null;
try {
FileWriter fw =new FileWriter(targetFile);
buffw =new BufferedWriter(fw);
for (File file : files) {
//把java文件的绝对路径写入文件
buffw.write(file.getAbsolutePath());
//换行
buffw.newLine();
//使用字符流注意刷新
buffw.flush();
}
}catch (IOException e) {
e.printStackTrace();
}finally {
try {
if (buffw !=null)
buffw.close();
}catch (IOException e) {
e.printStackTrace();
}
}
}
}
PrintStream 和 PrintWriter
A PrintStream adds functionality to another output stream, namely the ability to print representations of various data values conveniently.
Two other features are provided as well. Unlike other output streams,
a PrintStream never throws an IOException;
instead, exceptional situations merely set an internal flag that can be tested via the checkError method. Optionally,
a PrintStream can be created so as to flush automatically;
this means that the flush method is automatically invoked after a byte array is written, one of the println methods is invoked,
or a newline character or byte ('\n') is written.
All characters printed by a PrintStream are converted into bytes using the platform's default character encoding.
The PrintWriter class should be used in situations that require writing characters rather than bytes.
大概的意思是说 PrintStream 相比其他的输出流增强了许多功能,也就是很方便的打印数据,另外 PrintStream 还可以自动刷新,也就是说一个字节数组被写入或者调用 println 方法或者写入了换行字符或者字节 \n 后这个 flush 方法会被自动调用
- PrintStream(File file)
- PrintStream(OutputStream out)
- PrintStream(OutputStream out, boolean autoFlush)
- PrintStream(String fileName)
- PrintStream(OutputStream out, boolean autoFlush, String encoding)
Prints formatted representations of objects to a text-output stream.
This class implements all of the print methods found in PrintStream.
It does not contain methods for writing raw bytes, for which a program should use unencoded byte streams.
Unlike the PrintStream class, if automatic flushing is enabled it will be done only when one of the println, printf,
or format methods is invoked, rather than whenever a newline character happens to be output.
These methods use the platform's own notion of line separator rather than the newline character.
Methods in this class never throw I/O exceptions, although some of its constructors may.
The client may inquire as to whether any errors have occurred by invoking checkError().
大概的意思是说,PrintWriter 类不像 PrintStream 类,如果设置了自动刷新 (PrintWriter(Writer out, boolean autoFlush) 或者通过 PrintWriter(OutputStream out, boolean autoFlush) 设置),只有当调用 println()printf() format() 方法才会被刷新,
而不是无论什么时候只要出现换行字符就会输出,这些方法使用的是平台自己的行分隔符标准,而不是使用换行字符。
- PrintWriter(File file)
- PrintWriter(String fileName)
- PrintWriter(OutputStream out)
- PrintWriter(OutputStream out, boolean autoFlush)
- PrintWriter(Writer out)
- PrintWriter(Writer out, boolean autoFlush)
public static void print()throws IOException{
//获取键盘输入
BufferedReader buffr =new BufferedReader(new InputStreamReader(System.in));
//目的是控制台
PrintWriter pw =new PrintWriter(System.out);
String value =null;
while((value=buffr.readLine())!=null){
pw.write(value);
//注意刷新
pw.flush();
}
pw.close();
buffr.close();
}
控制太输出如下:
发现他没有换行,看上去不美观:怎么实现换行呢?我们来看一下这两个个方法
- println(String x)
- println()
API 是这样解释 println(String x) 方法的:
Prints a String and then terminates the line.
This method behaves as though it invokes print(String) and then println().
先打印字符串然后终止这行,也就是先调用 print(String str) 方法然后在调用 println() 方法.
API 是这样解释 println() 方法的:
Terminates the current line by writing the line separator string.
The line separator string is defined by the system propertyline.separator,
and is not necessarily a single newline character ('\n').
也就是通过行分隔符终止当前行,行分隔符通过系统属性 line.separator 设置的而不需要简单的换行符 '\n'
是不是我们通过 println();方法就可以解决上面的问题呢?
while((value=buffr.readLine())!=null){
pw.write(value);
pw.println();//终止一行
//手动刷新
pw.flush();
}
PrintWriter pw =new PrintWriter(System.out,true);//设置自动刷新
String value =null;
while((value=buffr.readLine())!=null){
pw.write(value);
pw.println();//因为println()printf()format()都会触发刷新
//pw.flush();
}
PrintWriter pw =new PrintWriter(System.out,true););//设置自动刷新
String value =null;
while((value=buffr.readLine())!=null){
pw.println(value);();//因为println()printf()format()都会触发刷新
}
PrintWriter pw =new PrintWriter(System.out,true););//设置自动刷新
String value =null;
while((value=buffr.readLine())!=null){
pw.write(value+"\r\n");//末尾加上换行符是否会触发自动刷新呢?
}
我们来测试一下:
//设置自动刷新
PrintWriter pw =new PrintWriter(System.out,true););
while((value=buffr.readLine())!=null){
//我们使用writer方法,里面的字符串参数加上行分隔符,
//因为java api里面说println()因为内部加上了行分隔符才会触发刷新的,
// 那么现在我们手工加上行分隔符会触发刷新吗?
pw.write(value+System.getProperty("line.separator"));
}
测试的结果还是不行!
我们来看一下 PrintWriter 的源代码是怎么定义 println(String) 方法的:
public void println(String x) {
synchronized (lock) {
print(x);//先打印数据
println();//再打印行分隔符,我们在进入println()是怎么定义的,
}
}
public void println() {
newLine();//打开是怎么样定义的
}
privatevoid newLine() {
try {
synchronized (lock) {
ensureOpen();
out.write(lineSeparator);//写入行分隔符
if (autoFlush)//判断是否设置刷新
out.flush();//如果设置为true,那么调用flush()方法
}
}catch (InterruptedIOException x) {
Thread.currentThread().interrupt();
}catch (IOException x) {
trouble =true;
}
}
经过查看 writer()方法的源代码,没有发现他去判断是否刷新,
结论:尽管我们在使用 writer(String) 方法的 String 参数后面加上了行分隔符,但是在 writer 方法里面根本不去判断是否设置了 autoFlush = true
所以我们在 writer(String) 方法的 String 参数后面加上了行分隔符也不能达到预期的效果!
如果我们想更加了解 PrintStream和 PrintWriter 的区别,查看源代码是最好的帮手。
PrintStream 是字节输出流的子类,PrintWriter是字符输出流的子类。
SequenceInputStream 序列流
- SequenceInputStream(Enumeration<? extends InputStream> e) 里面传一个Enumeration里面的元素使用了泛型限定.
- SequenceInputStream(InputStream s1,InputStream s2) 里面传入两个字节输入流对象
实例: 怎么把 3 个文件的内容输入到一个文件中?
//通过Vector可以获取Enumeration
Vector<InputStream> vector = new Vector<InputStream>();
vector.add(new FileInputStream("C:\\1.txt"));
vector.add(new FileInputStream("C:\\2.txt"));
vector.add(new FileInputStream("C:\\3.txt"));
//实例化合并流
SequenceInputStream sequence = new SequenceInputStream(vector.elements());
InputStreamReader isr = new InputStreamReader(sequence);
BufferedReader fr=new BufferedReader(isr);
BufferedWriter bw = new BufferedWriter(new FileWriter("C:\\123.txt"));
String value = null;
while((value=fr.readLine())!=null){
bw.write(value);
bw.newLine();
}
bw.close();
sequence.close();
FileInputStream 实现文件切割
publicstatic void cut()throws Exception {
InputStream is =new FileInputStream("C:\\mp3\\卓依婷- 好人好梦.mp3");
OutputStream os =null;
byte[] buffer =new byte[1024*1024];
int len=0;
int name = 1;
while ((len=is.read(buffer))!=-1) {
//每一次循环都会生成一个文件,这样就实现了切割
os =new FileOutputStream("C:\\mp3\\part\\"+(name++)+".part");
//每个文件写1M,最后一个文件可能没有1M
os.write(buffer,0,len);
os.close();
}
is.close();
}
publicstatic void merger()throws Exception {
List<InputStream> list =new ArrayList<InputStream>();
for (int i = 1; i <= 4; i++) {
list.add(new FileInputStream("C:\\mp3\\part\\" + (i) +".part"));
}
final Iterator<InputStream> iterator = list.iterator();
Enumeration<InputStream> enumeration =new Enumeration<InputStream>(){
public boolean hasMoreElements() {
return iterator.hasNext();
}
public InputStream nextElement() {
return iterator.next();
}
};
SequenceInputStream sequence =new SequenceInputStream(enumeration);
OutputStream os =new FileOutputStream("C:\\mp3\\part\\卓依婷- 好人好梦.mp3");
byte[] buffer =new byte[1024];
int len = 0;
while((len=sequence.read(buffer))!=-1){
os.write(buffer,0,len);
}
os.close();
sequence.close();
}
如果你觉得本文帮助到你,给个关注和赞呗!
您还可以查看我的 Github 查看 Java 技术栈:https://github.com/chiclaim/Java
不仅包括 Java I/O,还有 Java 虚拟机、多线程、集合框架。由于篇幅原因,只展示下,Java I/O 部分: