注意:这里仅仅描述了基本的使用方法,并没有涉及到NIO中的东西,有关于NIO方面的东西,放到之后的博客中描述。RandomAccessFile放到之后再进行描述
File
在文件系统中,文件名是用于定位存储位置 元数据:描述数据的数据,在这里我们将一个文件当作一个数据,那么文件的属性就是元数据。
java.io.File 类代表与当前系统平台无关的文件和目录
File 类的一个实例就代表一个文件或目录
File 类提供了判断 其实例是文件还是目录的方法
File 类提供了可以操作文件系统中的文件和目录的方法
File 类仅代表文件或目录,不支持对文件的内容进行修改
构造方法
File( String pathname )
通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例
File( String parent , String child )
根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例
File( File parent , String child )
根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例
File( URI uri )
通过将给定的 file: URI 转换为一个抽象路径名来创建一个新的 File 实例
但是我们在使用的时候,最经常使用的就是传一个路径的File构造方法。
常量
public static final char separatorChar
与系统有关的默认名称分隔符(⽂文件系统中的不不同层次的路路径之间的分隔符)
public static final String separator
与系统有关的默认名称分隔符,为了了⽅便,它被表示为一个字符串
public static final char pathSeparatorChar
与系统有关的路路径分隔符(环境变量量PATH的取值中不同部分之间的分隔符)
public static final String pathSeparator
与系统有关的路路径分隔符,为了了⽅便,它被表示为一个字符串
方法测试
String path = "C:/Windows/notepad.exe" ;
// 根据给定的目录的路径来创建一个对象 表示该目录的Java对象
File directory = new File(path) ;
System.out.println("File所表示的目录或文件是否存在 :" + directory.exists() );
System.out.println("是否是一个文件 : " + directory.isFile() );
System.out.println( "是否是一个目录 : " + directory.isDirectory() );
System.out.println("是否是隐藏的:" + directory.isHidden() );
System.out.println("是否是绝对路径:" + directory.isAbsolute() );
// length方法返回的字节数,如果需要转成KB或其他单位,需要进行换算(仅对文件有效,对目录无效)
System.out.println("文件的长度是:" + directory.length()/1024 );
path = "C:\\JavaApplication\\mysql-5.7.17-winx64" ;
directory = new File( path ) ;
String[] names = directory.list() ;
for (String s : names) {
System.out.print(s + "\t");
}
System.out.println();
File[] fileNames = directory.listFiles() ;
for (File f : fileNames) {
System.out.print(f.toString() + "\t");
}
System.out.println();
path = "C:/Windows/notepad.exe" ;
File f = new File(path) ;
System.out.println("文件名或目录名: " + f.getName() );
System.out.println("存放路径 : " + f.getParent() );
System.out.println("绝对路径 :" + f.getAbsolutePath() );
System.out.println("最后修改的毫秒 :" + f.lastModified() );
System.out.println( "最后修改的时间 :" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date( f.lastModified() )));
System.out.println("文件或目录是否可读 :" + f.canRead() );
System.out.println("文件或目录是否可写 :" + f.canWrite() );
System.out.println("文件或目录是否可以执行 :" + f.canExecute() );
/**
* 在Eclipse环境下运行含有main方法的Java程序,默认的当前路径是当前工程
* 注意路径的规范化形式
*/
path = "." ;
f = new File( path ) ;
System.out.println( f.getAbsolutePath() );
path = "src" ;// 表示当前路径下的src目录
f = new File( path ) ;
System.out.println( "获取绝对路径:" + f.getAbsolutePath() );
f = new File("..");
System.out.println( "获取绝对路径:" + f.getAbsolutePath() );
System.out.println("获取规范化形式的路径:" + f.getCanonicalPath() );
f = new File( "/" ) ;
System.out.println(f.getAbsolutePath() );
System.out.println(f.getCanonicalFile());
/**
* 创建新文件、删除新文件
*/
path = "." ;
f = new File( path ) ;
if( f.canWrite() ) {
// 在f对应的目录中创建一个hello.txt文件
// 在内存中创建一个表示f下的hello.txt对应的文件的Java对象
File file = new File( f , "hello.txt") ;
if ( file.exists()) {
file.delete() ;
}
// 在磁盘上 创建一个file对象对应的新文件
boolean b = file.createNewFile() ;
System.out.println( b );// 如果已经存在或没有权限则创建失败
}
/**
* 创建目录、删除目录( delete可以删除空目录)
*/
if( f.canWrite() ) {
File file = new File( f , "kaka") ;
if( file.exists() && file.isDirectory() ) {
boolean b = file.delete() ;
System.out.println( b ? "目录删除成功" : "目录删除失败" );
}
boolean b = file.mkdir() ; // 创建一个新目录
System.out.println( b ? "目录创建成功" : "目录创建失败");
}
/**
* mkdir可以创建一个子目录
* mkdirs 可以创建多层子目录
*/
if( f.canWrite() ) {
File file = new File( "kaka/kakaTM/kakTTMM");
file.mkdirs() ;
File dest = new File("kaka/kakaTM/kakTTMMMM") ;
// 将file的名称重命名为dest对应的名称
file.renameTo(dest) ;
}
File s = new File("./hello.txt") ;
File d = new File("C:/abc.txt") ;
s.renameTo(d) ; // 剪切操作( 强烈不建议操作 )
File kak = new File("kaka") ;
kak.deleteOnExit(); // 虚拟机退出之后再删除
Thread.sleep(30000 );// 可以在这里进行测试
文件过滤器
可以根据条件(最后修改时间、长度、名字等)进行过滤。
File dof = new File("C:/test") ;
if( dof.exists() && dof.isDirectory() ) {
FilenameFilter fnf = new FilenameFilter() {
[@Override](https://my.oschina.net/u/1162528)
public boolean accept(File dir, String name) {
if( name.endsWith("java")) {
return true ;
}
return false;
}
};
String[] fileList = dof.list(fnf) ;
System.out.println( fileList.length );
for (String s : fileList) {
System.out.println( s );
}
}
File dof = new File("C:/test") ;
if( dof.exists() && dof.isDirectory() ) {
FileFilter fnf = new FileFilter() {
[@Override](https://my.oschina.net/u/1162528)
public boolean accept(File pathname) {
if( pathname.isFile() && pathname.getName().endsWith(".java")) {
return true ;
}
return false;
}
};
File[] fileList = dof.listFiles(fnf);
System.out.println( fileList.length );
for (File s : fileList) {
System.out.println( s );
}
}
练习:可以通过遍历获取C盘下的所有文件的名字。
字节输入输出流
InputStream是所有字节输入流的父类。
注意看构造
我们可以利用FileInputStream来测试InputStream中的方法
File file = new File("out.txt") ;
InputStream inStream = null ;
System.out.println( inStream );
if( file.exists() && file.isFile() ) {
inStream = new FileInputStream(file) ;
System.out.println( inStream );
// int b = inStream.read() ; // 范围0~255,将byte数字进行"翻译"成int值
// System.out.println( b );
int b ;
do {
// read方法负责读取一个字节,
// 如果没有到达流的末尾,则返回读取到的数据
// 如果到达流的末尾,则返回-1
b = inStream.read() ; // 一次读取一个字节
System.out.println( b );
}while( b!=-1 );
}
inStream.close();
这里一次读取一个字节,解析出来的全是数字,如果转成char类型,看不懂。所以可以使用数组,表示一次多读取几个字节的方式来操作。
File file = new File("out.txt") ;
InputStream inStream = null ;
System.out.println( inStream );
if( file.exists() && file.isFile() ) {
inStream = new FileInputStream(file) ;
System.out.println( inStream );
// 获得下一次调用方法之前可以不受阻塞的从此输入流中读取估计字节数
int size = inStream.available() ;
byte[] bytes = new byte[size] ;
int n ;
/*do {
// read( byte[] bytes )方法负责读取n个字节,
// 如果没有到达流的末尾,则返回读取到的字节数(读取到几个字节就返回几)
// 如果读取到内容了,则将读取到的字节放入到数组中(读取到几个,就放入几个)
// 如果到达流的末尾,则返回-1
n = inStream.read(bytes ) ; // 一次读取一个字节
System.out.println( "读取到的字节数:"+n );
String s = new String(bytes , 0 , n ) ;
System.out.println( s );
}while( n!=-1 );
*/
while( (n = inStream.read(bytes)) != -1 ) {
String s = new String( bytes , 0 , n) ;
System.out.println( s );
}
}
System.out.println( inStream.markSupported() );
inStream.close();
我们可以看到FileInputStream是不支持做标记的,我们后续再说。那么我们的FileInputStream就看完了。
FileOutputStream
此抽象类是表示输出字节流的所有类的超类。输出流接受输出字节并将这些字节发送到某个接收器。
需要定义 OutputStream 子类的应用程序必须始终提供至少一种可写入一个输出字节的方法。
public static void main(String[] args) throws Exception {
File file = new File("file.txt") ;// 第一个参数指示输出到哪里去
boolean append = false ; // 如果第二个参数是true表示追加,如果是false表示覆盖
OutputStream os = new FileOutputStream(file, append) ;
// 输出单个字节(如果是int类型的整数,则忽略高24位,只留低8位)
os.write(97);
os.write(378);
byte[] bytes = "卡卡他妈".getBytes() ;
System.out.println( bytes.length );
// 将这个字节数组通过输出流 输出到文件中
os.write(bytes);
// 将字节数组中的一部分输出到文件中 write( bytes , start, n)[start , start+n)
os.write(bytes,3 , 3);
os.close();
}
这样我们就会使用了OutputStream这个类中的方法。
复制文件
public static void main(String[] args) throws Exception {
File source = new File("G:\\一禅壁纸\\电脑壁纸\\桌面背景03.jpg") ;
File target = new File( source.getName() ) ;
FileInputStream in = new FileInputStream(source) ;
FileOutputStream out = new FileOutputStream( target ) ;
int n ; // 声明一个变量,用来记录读取到的字节数
byte[] bytes = new byte[128] ;
while( (n = in.read(bytes ) ) != -1 ) {
// out.write(bytes);
out.write(bytes, 0, n);
}
out.close();
in.close();
}
当然,我们可以看一下复制时间。
BufferedInputStream
BufferedInputStream 为另一个输入流添加一些功能,即缓冲输入以及支持 mark 和 reset 方法的能力。在创建 BufferedInputStream 时,会创建一个内部缓冲区数组。
public static void main(String[] args) throws Exception {
InputStream in = new FileInputStream("src/bufferedStream/TestBufferedStream1.java") ;
// super(in)--->this.in = in ;
// this.buf = new byte[8192] ; // 内部有一个字节数组
BufferedInputStream bis = new BufferedInputStream(in) ;
byte[] bytes = new byte[100] ;
int n;
while((n=bis.read(bytes))!=-1 ) {
String s = new String( bytes , 0 , n );
System.out.print(s);
}
bis.close();
in.close();
}
public static void main(String[] args) throws Exception {
InputStream in = new FileInputStream("bufferIn.txt") ;
BufferedInputStream bis = new BufferedInputStream(in) ;
int n;
while((n=bis.read())!=-1 ) {
char ch = (char)n;
System.out.print( ch );
if( bis.markSupported() ) {// 判断是否支持mark和reset操作
if(ch=='s') {
// this.marklimit = readlimit;// this.maklimit =250
// this.markpos = pos;
bis.mark(250);
}
}
}
System.out.println();
if(bis.markSupported() ) {
bis.reset();
int b;
while((b=bis.read())!=-1 ) {
char ch = (char)b;
System.out.print( ch );
}
}
bis.close();
in.close();
}
/**
* 向缓冲字节输出流中输出数据,如果没有close和flush方法,可能导致数据不被输出
*/
public class TestBufferedStream3 {
public static void main(String[] args) throws Exception {
OutputStream out = new FileOutputStream("buffer.txt") ;
BufferedOutputStream bos = new BufferedOutputStream(out) ;
bos.write(97);
bos.write('b');
bos.write(100);
// 调用flush方法将缓冲区的内容进行刷出
// bos.flush();
bos.close();// close方法中调用了flush方法
}
}
字符输入输出流
Reader
用于读取字符流的抽象类。子类必须实现的方法只有 read(char[], int, int) 和 close()。 因为是抽象类,所以不能new对象,可以找它的子类:FileReader
public class TestReader {
public static void main(String[] args) throws Exception {
String file = "src/reader/TestReader.java" ;
// 创建一个字符输入流,一次可以读取一个字符
Reader reader = new FileReader(file) ;
int ch ;
// Reader中的read()可以返回一个字符(以整数形式返回)
// 如果读到流的末尾,返回-1
while( (ch = reader.read() ) != -1 ) {
// 将得到的整数形式的字符强制转成char类型
char c = (char)ch ;
System.out.print(c);
}
}
}
public static void main(String[] args) throws Exception {
String file = "src/reader/TestReader2.java" ;
Reader reader = new FileReader(file) ;
char[] chars = new char[100] ;// 表示100个字
int ch ;
// Reader中的read(char[] charArray)可以从流中读取n个字节到数组中
while( (ch = reader.read( chars ) ) != -1 ) {
// 将本次读取到的字符构造称字符串
String s = new String(chars, 0, ch) ;
System.out.print(s);
}
reader.close();
}
Writer
public static void main(String[] args) throws Exception {
String filename = "writer.txt" ;
boolean append = false ;
Writer w = new FileWriter(filename , append ) ;
w.write(97);
w.write('\n');
w.write("helloworld");
w.write('\n');
char[] chars = {'k','k','T','M'} ;
w.write(chars);
w.write(chars, 2,1 );
w.close();
}
public static void main(String[] args) throws Exception {
String filename = "writer.txt" ;
boolean append = false ;
Writer w = new FileWriter(filename , append ) ;
w.append("hello") ;
w.append('k') ;
w.write("TM");
w.close();
}
BufferedReader&&BufferedWriter
public static void main(String[] args) throws Exception {
// 创建一个可以读取文件内容的字符输入流( 节点流 )
Reader r = new FileReader("buffer.txt") ;
// 创建一个带有缓冲功能的字符输入流( 它提供了额外的功能)
// BufferedReader实例内部一个可以容纳8192个字符的char数组
BufferedReader br = new BufferedReader( r ) ;
String s ;
while( (s = br.readLine() ) != null ) {
System.out.println( s );
}
br.close();
r.close();
}
public static void main(String[] args) throws Exception {
Writer w = new FileWriter("buffer.txt");
// BufferedWriter内部有一个可以容纳8192个字符的char数组
BufferedWriter bw = new BufferedWriter(w) ;
bw.write("hello,kaka");// 向缓冲区中写入内容
// 刷出缓冲区的内容到目标输出流
bw.flush();
bw.close();
w.close();
System.out.println( w.toString() );
}
InputStreamReader && OutputStreamWriter
这两个流就是对应的转换流,是字节流和字符流之间的转换。
/**
*转换流(InputStreamReader)将字节输入流转换成字符输入流
*/
public class TestInputStreamReader1 {
public static void main(String[] args) throws Exception {
String fileName = "src/conver/TestInputStreamReader1.java";
// 创建一个字节输入流
InputStream in = new FileInputStream(fileName) ;
// 将字节输入流转换称字符输入流
InputStreamReader isr = new InputStreamReader(in) ;
// byte[] bytes = new byte[8] ;
// int b ;
// while( (b = in.read(bytes)) != -1 ) {
// String s = new String( bytes , 0 , b );
// System.out.print(s);
// }
int n ;
// 一次读取一个字符(以整数形式返回),保存到ch变量中,然后比较是否等于-1(如果是-1,表示结束)
while( (n = isr.read()) != -1 ) {
System.out.print( (char)n );
}
in.close();
}
}
public static void main(String[] args) throws Exception {
// 将标准输入流存储到变量in中
InputStream in = System.in ;
// int n ;
// while( (n = in.read() ) != -1 ) {
// System.out.println((char)n);
// }
// 将字节输入流转换成字符输入流
InputStreamReader r = new InputStreamReader(in ) ;
int ch ;
while( (ch = r.read() ) != -1 ) {
System.out.print((char)ch);
}
r.close();
in.close();
}
public static void main(String[] args) throws Exception {
// 将标准输入流存储到变量in中
InputStream in = System.in ;
// 将字节输入流转换成字符输入流
InputStreamReader r = new InputStreamReader(in ) ;
// 包装一个字符缓冲流
BufferedReader br =new BufferedReader(r) ;
String ch ;
while( (ch = br.readLine() ) != null ) {
System.out.print(ch);
if( "byebye".equalsIgnoreCase(ch)) {
System.exit(0);
}
}
r.close();
in.close();
}
OutputStreamWriter
/**
* 将字符输出流转换成字节输出流
*/
public class TestOutputStreamWriter {
public static void main(String[] args) throws IOException {
// 创建一个字节输出流,输出到文本文件中
OutputStream o = new FileOutputStream("convert.txt");
// 将字符输出流转成字节输出流
OutputStreamWriter osw = new OutputStreamWriter( o ) ;
osw.write("哈哈哈哈哈");
osw.write('k');
osw.write('\n');
osw.close();
o.close();
}
}
/**
*读取一个UTF-8编码的文件,将它转成GBK编码后重新输出到另外一个文件中
*/
public class TestOutputStreamWriter2 {
public static void main(String[] args) throws IOException {
// 读取一个文本文件
InputStream inStream = new FileInputStream("convert.txt") ;
// 创建一个转换流,并指定相应的字节输入流和编码名称
// 在将字节转换成字符时,采用编码名称指定的编码完成
InputStreamReader isr = new InputStreamReader( inStream ,"UTF-8" ) ;
// 创建一个可以输出字节到指定文件的字节输出流
OutputStream outputStream = new FileOutputStream("convert-gbk.txt");
// 创建一个以指定字节流为输出目标的转换流( 字节转字符 )
// 并指定将字符转换成字节时,使用的编码名称
OutputStreamWriter osw = new OutputStreamWriter(outputStream, "GBK") ;
int ch ;
// 从字符输入流中一次读取一个字符
while( ( ch = isr.read() ) != -1 ) {
// 通过字符输出流将读取到的字符重新输出
osw.write(ch); // 将单个字符写出到Writer流
}
osw.close();
outputStream.close();
isr.close();
inStream.close();
}
}
对象序列化
/**
* 如果希望完成序列化操作,需要实现java.io.Serializable接口
*/
public class Student implements Serializable{
/**
* serialVersionUID 相当于一个类的身份证编号
* 在序列化时,会将该编号一起输出到相应的流中
* 等到反序列化时(读取流还原对象),会检查相应的类是否存在(会检查该编号)
*/
private static final long serialVersionUID = -3227384916215757351L;
private Integer id ;
private String name ;
private char gender ;
private Date bithdate ;
// getter and setter
}
/**
* 序列化( Serialization)
* 将一个Java对象以特定的字节序列输出到某个流中
* 通过 ObjectOutputStream类的writeObject(obj)来实现
* 被写出的那个对象对应的类需要实现java.io.Serialization接口
*/
public class ObjectSerialization1 {
public static void main(String[] args) throws IOException {
final Calendar c = Calendar.getInstance() ;
Student s = new Student() ;
s.setId(9527);
s.setName("华安");
s.setGender('男');
c.set(1888, 8, 8, 8, 8, 8);
s.setBithdate(c.getTime());
OutputStream out = new FileOutputStream("student.obj") ;
ObjectOutputStream oos = new ObjectOutputStream(out) ;
// 保存学生对象
oos.writeObject(s);
oos.close();
out.close();
}
}
/**
* 反序列化
* 就是读取一个流中的数据,将它还原(重构)成相应的对象
* 重构时,就会检查该对象对应的类的serialVersionUID
* 反序列化通过ObjectInputStream来实现
*/
public class ObjectDeserialization1 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
InputStream in = new FileInputStream("student.obj") ;
ObjectInputStream ois = new ObjectInputStream(in) ;
// 从已知的字节流中读取某个对象对应的数据
Object o = ois.readObject() ;
System.out.println( o );
if( o instanceof Student) {
Student s = (Student) o ;
System.out.println( s.getName() );
}
ois.close();
in.close();
}
}