在java.io包中,File是唯一一个与文件本身操作(创建、删除、取得信息...)有关的程序类。
构造方法:
public File(String pathname);//文件在pathname路径下
public File(String parent,String child),设置父路径和子路径。
其它方法:
public boolean createNewFile() throws IOException;创建一个新文件。
public boolean exists();判断文件是否存在。
public boolean delete();删除文件
package com.xunpu.file;
import java.io.File;
import java.io.IOException;
/**
*File有关方法的使用
*/
public class Demo1 {
public static void main(String[] args) {
//在E:\\DEMO1目录下创建Demo1.txt文件
File file=new File("E:\\DEMO1\\aaa.txt");
//如果文件存在,就删除。
if(file.exists()){
file.delete();
System.out.println("文件已存在,删除");
}else {
try {
boolean isSuccess=file.createNewFile();
if(isSuccess){
System.out.println("文件不存在,重新创建文件,创建成功");
}else{
System.out.println("文件不存在,重新创建文件失败!!");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
不同操作系统中路径分隔符不同,Linux下是"/",而Windows下是"\",为了解决这个问题,通常使用File类的一个常量public static final String separator来描述。使用为:File.seperator
public String getParent();取得父路径
public File getParentFile();取得父File对象
public boolean mkdirs() 创建目录(不论有多少级,都会创建)
package com.xunpu.file;
import java.io.File;
/**
* 目录有关方法的使用
*/
public class Demo2 {
public static void main(String[] args) {
//设置file为Demo1.java文件
File file=new File("D:"+File.separator+"Java项目"+File.separator+"javaIO"+File.separator+"src"
+File.separator+"main"+File.separator+"java"+File.separator+"com"+File.separator+"xunpu"+File.separator+
"file"+File.separator+"Demo1.java");
System.out.println(file.getParent());//取得父路径
System.out.println(file.getParentFile());//取得父File对象
file=new File("E:"+File.separator+"JavaFile"+File.separator+"Directory"+File.separator+"bbb");
if(!file.exists()) {
boolean isMkdir = file.mkdirs();
if (isMkdir) {
System.out.println("文件夹不存在,现重新创建成功");
}else{
System.out.println("文件夹不存在,现重新创建失败");
}
}else{
System.out.println("文件夹已经存在");
}
}
}
最终在E盘递归创建文件夹。
public boolean isFile();判断路径是否是文件
public boolean isDirectory();判断路径是否是目录
public long length();取得文件大小(字节)
public long lastModified();最后一次修改日期
package com.xunpu.file;
import java.io.File;
import java.util.Date;
/**
* 文件信息的有关方法使用
*/
public class Demo3 {
public static void main(String[] args) {
File file=new File("E:"+File.separator+"JavaFile"+File.separator+"Directory"+File.separator+"bbb");
//判断是否是文件
if(file.isFile()){
System.out.println("bbb是文件");
}
//判断是否是目录/文件夹
if(file.isDirectory()){
System.out.println("bbb是目录或者文件夹");
}
System.out.println("文件的大小为:"+file.length()+"字节");//计算的是其内文件夹的大小
long time=file.lastModified();//获取文件最后一次修改的时间,返回值是long类型。
//将long类型转换为Date类型
Date date=new Date(time);
System.out.println("bbb最后一次修改的时间为:"+date);
}
}
需求:给定一个文件夹名,要求打印出该文件夹下所有的子文件的名称,大小和修改时间。
package com.xunpu.file;
import java.io.File;
import java.util.Date;
/**
* 综合案例:指定文件夹,要求列出文件夹中所有文件夹的大小
*/
public class Demo4 {
public static void main(String[] args) {
File file=new File("D:"+File.separator+"Java项目"+File.separator+"javaIO"+File.separator+"" +
"src"+File.separator+"main"+File.separator+"java"+File.separator+"com"+File.separator
+"xunpu");
listAllFileInfo(file);
}
private static void listAllFileInfo(File file) {
if(file==null){
return;
}
if(file.isFile()){
System.out.print(file);
System.out.println(" 文件大小为:"+file.length()+"字节 文件最后一次的修改日期为:"
+new Date(file.lastModified()));
}else if(file.isDirectory()){
File[] files=file.listFiles();
for(File item:files){
listAllFileInfo(item);
}
}
}
}
现在的代码可能会发生线程阻塞问题,当前的操作是在main线程下进行的。如果listAllFileInfo()没有完成,main后序的操作是无法进行的。这种耗时的操作让主线程出现了阻塞,导致后续代码无法正常执行完毕。此时,不想发生阻塞,最好让lsitAllFileInfo()在另一个线程中完成。
package com.xunpu.file;
import java.io.File;
import java.util.Date;
/**
* 不产生阻塞,打印出文件的详细信息
*/
public class Demo5 {
public static void main(String[] args) {
Thread thread=new Thread(){
@Override
public void run(){
File file=new File("D:"+File.separator+"Java项目"+File.separator+"javaIO"+File.separator+"" +
"src"+File.separator+"main"+File.separator+"java"+File.separator+"com"+File.separator
+"xunpu");
listAllFileInfo(file);
}
};
thread.start();
}
private static void listAllFileInfo(File file) {
if(file==null){
return;
}
if(file.isFile()){
System.out.print(file);
System.out.println(" 文件大小为:"+file.length()+"字节 文件最后一次的修改日期为:"
+new Date(file.lastModified()));
}else if(file.isDirectory()){
File[] files=file.listFiles();
for(File item:files){
listAllFileInfo(item);
}
}
}
}
File类不支持文件内容处理。如果要处理文件内容,必须通过流的操作模式来完成。
按输入/输出分为:输入流:InputStream和Reader 输出流:OutputStream和Writer
按字节流/字符流:字节流:InputStream和OutputStream 字符流:Writer和Reader
本质区别:字节流是原生操作,而字符流是经过处理后的操作。
在进行网络数据传输和磁盘保存数据时,只支持字节的数据类型。
字符更加适合处理中文。
注意:IO操作属于资源处理,所有的资源处理操作(IO操作、数据库操作、网络)最后必须要进行关闭。
说明:
1)ByteArrayOutputStream/ByteArrayInputStream:把字节数组转换为输出流/输入流
2)FileOutStream/FileInputStream:从文件中写/读取数据。
3)PipedOutputStream/PipedInputStream:连接一个PipedInutStream或PipedOutputStream
4)ObjectOutputStream/ObjectInputStream:对象输出流/对象输入流,常用于序列化中。
5)FilterOutputStream/FilterInputStream:装饰器,扩展其它输出流/输入流的功能。
6)SequenceInputStream:把几个输入流转换为一个输出流。
OutputStream:(写数据有关的方法)
void write(int b);//写入一个字节
void write(byte[] b);//把参数b指定的字节数组中的所有字节写到输入流。
void write(byte[] b,int off,int len);//把参数b指定的字节数组中的若干字节写到输出流,参数off指定字节数组开始的起始下标,从这个位置开始输出由参数len指定数目的字节。
void close();//关闭输出流
void flush();//OutputStream本身的flush()不执行任何操作,它的一些带有缓冲区的子类(比如BufferedOutputStream和PrintStream类)覆盖了flush()。通过带缓冲区的输出流写数据时,数据先保存在缓冲区中,积累到一定程度才会真正写到输出流中。缓冲区通常由字节数组实现,实际上指一块内存空间。flush()强制把缓冲区中的数据写到输出流中。
InputStream:(读数据有关的方法)
int read();//读一个字节,并把它转换为0~255之间的整数并返回。
int read(byte[] b);//读若干字节,并保存到参数b指定的字节数组中,返回字节数;如果读到末尾,返回-1.
int read(byte[] b,int off,int len);//读若干字节,从off处开始,指定len个字节,返回实际读取的字节数。
void close();//同OutputStream
int available();//返回可以从输入流读取的字节数
skip(long n);//从输入流中跳过参数n指定的字节数目。
boolean markSupported();//判断流是否支持重复读入数据。返回true,说明可以在流上设置标记。
void mark(int readLimit);//从流的当前位置开始设置标记,readLimit在流上指定标记的字节数。
void reset();//使输入流重新定位到刚才做标记的起始位置。
public FileOutputStream(File file) throws FileNotFoundException;接收File类(覆盖)
public FileOutputStream(File file,boolean append);接收File类(追加)
文件操作的基本步骤:
1)根据文件路径创建File类对象。
2)根据字节流或字符流的子类实例化父类对象。
3)进行数据的读取或写入操作。
4)关闭流(close())
package com.xunpu.myio;
import java.io.*;
/**
*文件的写入和输出操作
*/
public class Test1 {
public static void main(String[] args) {
//1.创建file对象
File file=new File("E:"+File.separator+"JavaFile"+File.separator+"Directory"+File.separator+"bbb"
+File.separator+"aaa.txt");
try {
//2.创建OuputStream对象(写数据)
OutputStream outputStream=new FileOutputStream(file);
//3.执行文件的写操作
String str="hello world";
byte[] bytes=str.getBytes();//将字符串转换为字符数组
outputStream.write(bytes);//写到文件中
//执行文件的读操作
//创建InputStream对象(读数据)
InputStream inputStream=new FileInputStream(file);
byte[] data=new byte[1024];//定义每次最多可以读1024个字节
int len=inputStream.read(data);//将读取的数据放入数组中
String res=new String(data,0,len);//在这里,可以修改len,控制输出的字符数
System.out.println("文件中的内容为:"+res);
res=new String(data,0,7);//hello w
System.out.println(res);
//4.关闭流
outputStream.close();
inputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
JDK1.7支持. 目的:自动进行关闭处理。 使用方法:必须结合try...catch使用.
package com.xunpu.myio;
/**
* AutoCloseable接口的使用:
* 1.创建一个类继承AutoCloseable接口
* 2.在try中定义子类
* 3.在try中执行有关方法
*/
class Message implements AutoCloseable {
public void close() throws Exception {
System.out.println("关闭资源");
}
}
public class Test2 {
public static void main(String[] args) {
try(Message message=new Message()) {//在try中定义对象,会自动给关闭。
message.close();//重复关闭,显示“多余的关闭”
} catch (Exception e) {
e.printStackTrace();
}
}
}
InputStream和OutputStream的定义:
public abstract class OutputStream implements Closeable, Flushable;
public abstract class InputStream implements Closeable;
public interface Closeable extends AutoCloseable;
可以看到这两个类都继承了Closeable接口,而Closeable接口又实现了AutoCloseable接口,因此,InputStream和OutputStream也都可以实现自动关闭,这只需要在try中定义即可。
package com.xunpu.myio;
import java.io.*;
/**
* InputStream和OutputStream的自动关闭
*/
public class TestAutoCloseable {
public static void main(String[] args) {
//1.创建file对象
File file=new File("E:"+File.separator+"JavaFile"+File.separator+"Directory"+File.separator+"bbb"
+File.separator+"aaa.txt");
//2.创建outputStream对象(向文件中追加内容)
try(OutputStream out=new FileOutputStream(file,true)) {
String msg="\nJava is best";//换行添加内容
byte[] data=msg.getBytes();
out.write(data);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
//创建inputstream对象
try(InputStream in=new FileInputStream(file)) {//自动关闭
//读
byte[] bytes=new byte[1024];
int len=in.read(bytes);
String res=new String(bytes,0,len);
System.out.println("文件内容为:"+res);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
说明:
1)CharArrayWriter/CharArrayReader:适配器,把字符数组转换为Writer(Reader),向字符数组中写字符(读取字符)。
2)BufferedWriter/BufferedReader:装饰器,为其它Writer(Reader)提供写(读)缓冲区。
3)StringWriter/StringReader:适配器,把StringBuffer转换为Writer(Reader),向StringBuffer中写字符(读取字符)。
4)PipedWriter/PipedReader:连接一个PipedReader/PipedWriter。
5)FilterWriter/FilterReader:装饰器,扩展其他Writer/Reader功能。
6)PrintWriter:装饰器,输出格式化数据。
7)OutputStreamWriter/InputStreamReader:适配器,将OutputStream转换为Writer(InputStream转换为Reader),可以指定数据汇的字符编码。
8)FileWriter/FileReader:向文件中写字符(读取字符)。
9)PushBackReader:装饰器,能够把读到的一个字符压回到缓冲区中。通常用作编译器的扫描器,在程序中很少用到。
Writer类(与写数据有关的方法):
public void write(char[] cbuf) throws IOException;//写入一个字符数组。
public abstract void write(char[] cbuf,int off,int len) throws IOException;//写入字符数组的一部分。
public void write(String str) throws IOException;//写一个字符串
public void write(String str,int off,int len) throws IOException;//写一个字符串的一部分。
public Writer append(CharSequence csq) throws IOException;//将指定的字符序列附加到此作者。
public Writer append(CharSequence csq,int start,int end) throws IOException;//将指定字符序列的子序列附加到此作者.
public Writer append(char c) throws IOException;//将指定字符添加到写对象中。
public abstract void flush() throws IOException;//刷新流。一个flush()调用将刷新Writers和OutputStreams链中的所有缓冲区。
public abstract void close() throws IOException;//关闭流,先刷新。 一旦流已关闭,进一步的write()或flush()调用将导致抛出IOException。 关闭以前关闭的流无效。
Reader类(与读数据有关的方法):
public int read(CharBuffer target) throws IOException;//尝试将字符读入指定的字符缓冲区。 缓冲区用作字符存储库:唯一的更改是put操作的结果。 不执行缓冲器的翻转或倒带。
public int read() throws IOException;//读一个字符 该方法将阻塞,直到字符可用,发生I / O错误或达到流的结尾。
public int read(char[] cbuf) throws IOException;//将字符读入数组。 该方法将阻塞,直到某些输入可用,发生I / O错误或达到流的结尾。
public abstract int read(char[] cbuf,int off,int len) throws IOExceptio;//将字符读入数组的一部分。 该方法将阻塞,直到某些输入可用,发生I / O错误或达到流的结尾。
public long skip(long n) throws IOException;//跳过字符 该方法将阻塞,直到某些字符可用,发生I / O错误或达到流的结尾。
public boolean ready() throws IOException;//告诉这个流是否准备好被读取。
public boolean markSupported();//告诉这个流是否支持mark()操作。 默认实现始终返回false。 子类应该覆盖此方法。
public void mark(int readAheadLimit) throws IOException;//标记流中的当前位置。 对reset()的后续调用将尝试将流重新定位到此位置。 并非所有字符输入流都支持mark()操作。
public void reset() throws IOException;//重置流。 如果流已被标记,则尝试在标记处重新定位。 如果流未被标记,则尝试以某种方式对特定流进行重置,例如通过将其重新定位到其起始点。 并不是所有的字符输入流都支持reset()操作,有些支持reset(),而不支持mark()。
public abstract void close() throws IOException;//关闭流并释放与之相关联的任何系统资源。 一旦流已关闭,进一步的read(),ready(),mark(),reset()或skip()调用将抛出IOException。 关闭以前关闭的流无效。
字符适合处理中文数据,有关字符流的定义如下:
public abstract class Writer implements Appendable, Closeable, Flushable;
public abstract class Reader implements Readable, Closeable;
它们也通过继承Closeable接口,间接实现AutoCloseable接口,可以使用try...catch实现自动关闭。Writer类比OutputStream类多继承了Appendable接口,可以实现追加字符。而OutputStream是通过FileOutputStream的构造方法,通过设置append参数为true来实现向文件中追加内容的。
package com.xunpu.myio;
import java.io.*;
public class Test3 {
public static void main(String[] args) {
//1.定义file对象
File file=new File("E:"+File.separator+"JavaFile"+File.separator+"Directory"+File.separator+"bbb"
+File.separator+"aaa.txt");
//2.定义writer类对象
try(Writer writer=new FileWriter(file,true)) {//writer对象自动关闭,向文件中换行添加内容
writer.append("\nToday is Friday!");
} catch (IOException e) {
e.printStackTrace();
}
//3.
try(Reader reader=new FileReader(file)){
char[] buf=new char[1024];
int len=reader.read(buf);//将文件的内容存入buf数组中
String res=new String(buf,0,len);
System.out.println("文件的内容为:"+res);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}