File类
概述
用来将文件或者文件夹封装成对象,方便对文件与文件夹的属性信息进行操作,File对象可以作为参数传递给流的构造函数,是文件和目录路径名的抽象表示形式。
构造方法
1. File f1 = new File(“x.txt”);// 将x.txt封装成file对象,可以将已有的和未出现的文件或文件夹封装成对象。
2. File f2 = new File(“d:\\dd\\cc”,”x.txt”);
3. File f = new File(“c:\\aa”); File f3 = new File(f,”x.txt”);
跨平台的目录分隔符:separator:与系统有关的默认名称分隔符。例:File f1 = new File(“d:”+File.separator+”x.txt”);
File类常见方法:
创建
boolean createNewFile();在指定位置创建文件,如果该文件已经存在,则不创建,返回false。和输出流不一样,输出流对象一建立就创建文件,而且如果文件已经存在,会被覆盖。会有异常。
File createTempFile(String prefix, String suffix);在默认临时文件目录中创建一个空文件,使用给定前缀和后缀生成其名称。
boolean mkdir();创建此抽象路径名指定的目录。也就是创建文件夹。
boolean mkdirs();创建多级文件夹。
注意:mkdir只可以创建一级目录。
删除
boolean delete();删除,失败返回false。如果文件正在被使用,则删除不了返回falsel。
void deleteOnExit();在程序退出时删除指定文件。
判断
compareTo();按字母顺序比较两个抽象路径名。比较文件名称。
boolean existe();文件是否存在。
isFile();是否是文件
isDirectory();是否是目录
isHidden();是否是隐藏
isAbsolute();是否是绝对路径,文件不存在也可以判断。
获取信息
getName():返回文件或目录的名称。
getPath():将此抽象路径名转换为一个路径名字符串。
getParent():返回父目录的路径名字符串,如果没有指定父目录,则返回null。
getAbsolutePath() :获取绝对路径
long lastModified() :获取最后一次修改的时间
long length():获取文件的大小
注意:getParent()方法返回的是绝对路径中的父目录,如果获取的是相对路径,则返回null。如果相对路径中有上一层目录,那么该目录就是返回结果。
相当于剪切的方法
renameTo(File dest):重新命名此抽象路径名表示的文件。
示例:
public static void method()
{
File f1 = new File("c:\\Test.java");
File f2 = new File("d:\\hehe.java");
f2.renameTo(f1);
}
文件列表
static File listRoots():列出可用的文件系统根。
File[] listFiles();返回一个抽象路径名数组,这些路径名表示此抽象路径名表示的目录中的文件。这个方法比较常用。
String[] list():返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中的文件和目录。
注意:调用list方法的file对象必须是封装了一个目录,该目录必须存在。
String[] list(FilenameFilter filter);返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中满足指定过滤器的文件和目录。
示例:只显示后缀为txt的文件
File dir = new File("d:\\java\\day01");
String[] arr = dir.list(new FilenameFilter()//定义匿名内部类
{
public boolean accept(File dir,String name)//复写FilenameFilter接口里的方法
{
return name.endsWith(".txt");
}
});
for(String name : arr)//定义循环
{
System.out.println(name);
}
递归
示例:带层次的列出指定目录下所有内容
import java.io.*;
class FileDemo
{
public static void main(String[] args)
{
File dir = new File("d:\\testdir");
showDir(dir,0);
}
public static String getLevel(int level)
{
StringBuilder sb = new StringBuilder();
sb.append("|--");
for(int x=0; x<level; x++)
{
sb.insert(0,"| ");
}
return sb.toString();
}
public static void showDir(File dir,int level)
{
System.out.println(getLevel(level)+dir.getName());
level++;
File[] files = dir.listFiles();
for(int x=0; x<files.length; x++)
{
if(files[x].isDirectory())
showDir(files[x],level);
else
System.out.println(getLevel(level)+files[x]);
}
}
}
因为目录中还有目录,所以只要使用同一个列出目录功能的函数完成即可。也就是还可以再次调用本功能,可以函数自身调用自身。这种表现形式,或者编程手法,称为递归。
注意:1,限定条件。2,要注意递归的次数,尽量避免内存溢出。
示例:删除带内容的目录
import java.io.*;
class RemoveDir
{
public static void main(String[] args)
{
File dir = new File("d:\\testdir");
removeDir(dir);
}
public static void removeDir(File dir)
{
File[] files = dir.listFiles();
for(int x=0; x<files.length; x++)
{
if(files[x].isDirectory())
removeDir(files[x]);
else
System.out.println(files[x].toString()+":-file-:"+files[x].delete());
}
dir.delete();
}
}
注意:java删除是不走回收站的。
示例:复制一个带内容的目录
import java.io.*;
public class CopyDirTest {
public static void main(String[] args) {
File src = new File("E:\\java\\javaTest");
File dest = new File("E:\\");
copyDir(src, dest);
}
public static void copyDir(File src, File dest) {
File newDir = new File(dest, src.getName());
newDir.mkdir();
File[] arr = src.listFiles();
for (File subfile : arr) {
if (subfile.isDirectory())
copyDir(subfile, newDir);
else
copyFile(subfile, new File(newDir, subfile.getName()));
}
}
private static void copyFile(File subfile, File file) {//复制文件
BufferedReader bufr = null;
BufferedWriter bufw = null;
try {
bufr = new BufferedReader(new FileReader(subfile));
bufw = new BufferedWriter(new FileWriter(file));
String line = null;
while ((line = bufr.readLine()) != null) {
bufw.write(line);
bufw.newLine();
bufw.flush();
}
} catch (IOException e) {
throw new RuntimeException("读写失败");
} finally {
try {
if (bufr != null)
bufr.close();
} catch (IOException e) {
throw new RuntimeException("读取关闭失败");
}
try {
if (bufw != null)
bufw.close();
} catch (IOException e) {
throw new RuntimeException("写入关闭失败");
}
}
}
}
示例:创建java文件列表
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
class JavaFileList
{
public static void main(String[] args) throws IOException
{
File dir = new File("d:\\java1223");
List<File> list = new ArrayList<File>();
fileToList(dir,list);
//System.out.println(list.size());
File file = new File(dir,"javalist.txt");
writeToFile(list,file.toString());
}
public static void fileToList(File dir,List<File> list)
{
File[] files = dir.listFiles();
for(File file : files)
{
if(file.isDirectory())
fileToList(file,list);
else
{
if(file.getName().endsWith(".java"))//只列出扩展名为.java的文件
list.add(file);
}
}
}
public static void writeToFile(List<File> list,String javaListFile)throws IOException
{
BufferedWriter bufw = null;
try
{
bufw = new BufferedWriter(new FileWriter(javaListFile));
for(File f : list)
{
String path = f.getAbsolutePath();
bufw.write(path);
bufw.newLine();
bufw.flush();
}
}
catch (IOException e)
{
throw e;
}
finally
{
try
{
if(bufw!=null)
bufw.close();
}
catch (IOException e)
{
throw e;
}
}
}
}
Properties对象
Properties是hashtable的子类,也就是说它具备了map集合的特点。而且,它里面存储的键值对都是字符串,所以它不需要泛型。它是集合中和IO技术相结合的集合容器。
特点:
可以用于键值对形式的配置文件。在加载数据时,需要数据有固定格式:键=值。
Properties存取
setProperty(String key, String value);调用 Hashtable的方法 put。他通过调用基类的put方法来设置键 -值对。
getProperty(String key);用指定的键在此属性列表中搜索属性。也就是通过参数 key,得到 key所对应的 value。
Set<String> stringPropertyNames();返回此属性列表中的键集。
load(InputStream inStream);将流中的数据加载进集合。从输入流中读取属性列表(键和元素对)。通过对指定的文件进行装载来获取该文件中的所有键 -值对。以供 getProperty ( String key) 来搜索。
原理:
1. 用一个流与数据文件关联
2. 读取一行数据,将该行数据用”=”进行切割
3. 等号左边作为键,右边作为值。存入Properties集合中即可
store(OutputStream out, String comments);将内存结果存入流中,并存在一个文件上。以适合使用 load方法加载到Properties表中的格式,将此 Properties表中的属性列表(键和元素对)写入输出流。与 load方法相反,该方法将键 -值对写入到指定的文件中去。
clear ();清除所有装载的键值对。该方法在基类中提供。
示例:用于记录应用程序运行次数,如果使用次数已到,给出注册提示。
import java.io.*;
import java.util.*;
class RunCount
{
public static void main(String[] args) throws IOException
{
Properties prop = new Properties();
File file = new File("count.ini");
if(!file.exists())
file.createNewFile();
FileInputStream fis = new FileInputStream(file);
prop.load(fis);
int count = 0;
String value = prop.getProperty("time");
if(value!=null)
{
count = Integer.parseInt(value);
if(count>=5)
{
System.out.println("您好,使用次数已到,请注册!!");
return ;
}
System.out.println("文件运行");
}
count++;
prop.setProperty("time",count+"");
FileOutputStream fos = new FileOutputStream(file);
prop.store(fos,"");//第二个参数是添注释信息
fos.close();
fis.close();
}
}
打印流
该流提供了打印方法,可以将各种数据类型的数据都原样打印。
特点:可以直接操作输入流和文件。
字节打印流
PrintStream:为其他输出流添加功能,使它们能够方便地打印各种数据值表现形式。
构造函数可以接收的参数类型:
1,file对象。File
2,字符串路径。String
3,字节输出流。OutputStream
字符打印流
PrintWriter:向文本输出流打印对象的格式化表示形式。此类实现在PrintStream中的所有print方法。
构造函数可以接收的参数类型:
1,file对象。File
2,字符串路径。String
3,字节输出流。OutputStream
4,字符输出流。Writer
序列流
SequenceInputStream:对多个流进行合并。
注意:SequenceInputStream(Enumeration<? extends InputStream> e);该参数必须是生成运行时类型为 InputStream对象的 Enumeration型参数。
示例:
import java.io.*;
import java.util.*;
class SequenceDemo
{
public static void main(String[] args) throws IOException
{
Vector<FileInputStream> v = new Vector<FileInputStream>();
v.add(new FileInputStream("c:\\1.txt"));
v.add(new FileInputStream("c:\\2.txt"));
v.add(new FileInputStream("c:\\3.txt"));
Enumeration<FileInputStream> en = v.elements();
SequenceInputStream sis = new SequenceInputStream(en);
FileOutputStream fos = new FileOutputStream("c:\\4.txt");
byte[] buf = new byte[1024];
int len =0;
while((len=sis.read(buf))!=-1)
{
fos.write(buf,0,len);
}
fos.close();
sis.close();
}
}
示例:切割文件,合并文件
import java.io.*;
import java.util.*;
class SplitFile
{
public static void main(String[] args) throws IOException
{
splitFile();//切割
merge();//合并
}
//合并图片
public static void merge()throws IOException
{
ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
for(int x=1; x<=3; x++)
{
al.add(new FileInputStream("D:\\"+x+".part"));
}
final Iterator<FileInputStream> it = al.iterator();
Enumeration<FileInputStream> en = new Enumeration<FileInputStream>()//匿名内部类
{
public boolean hasMoreElements()
{
return it.hasNext();
}
public FileInputStream nextElement()
{
return it.next();
}
};
SequenceInputStream sis = new SequenceInputStream(en);
FileOutputStream fos = new FileOutputStream("D:\\0.bmp");
byte[] buf = new byte[1024];
int len = 0;
while((len=sis.read(buf))!=-1)
{
fos.write(buf,0,len);
}
fos.close();
sis.close();
}
//切割图片
public static void splitFile()throws IOException
{
FileInputStream fis = new FileInputStream("D:\\1.bmp");
FileOutputStream fos = null;
byte[] buf = new byte[1024*1024];//设置每份的大小
int len = 0;
int count = 1;
while((len=fis.read(buf))!=-1)
{
fos = new FileOutputStream("D:\\"+(count++)+".part");//起一个扩展名
fos.write(buf,0,len);
fos.close();
}
fis.close();
}
}
操作对象的流:
可以将堆内存中对象存入硬盘上,这就叫对象的持久化存储(也叫对象的序列化)。
ObjectInputStream
ObjectOutputStream:将Java对象的基本数据类型和图形写入OutputStream。可以使用 ObjectInputStream读取(重构)对象。
在序列化的时候为了方便可以给被操作的类定义一个固定标识static final long serialVersionUID = 1L;
serialVersionUID作用是序列化时保持版本的兼容性,即在版本升级时反序列化仍保持对象的唯一性。
序列化时为了保持版本的兼容性,即在版本升级时反序列化仍保持对象的唯一性。有两种生成方式:
1. 一个是默认的1L。
2.一个是根据类名、接口名、成员方法及属性等来生成一个64位的哈希字段。
注意:静态是不可以被序列化的,如果你想让非静态的也不序列化可以加修饰符transient。被操作的对象需要实现Serializable(标记接口):类通过实现Serializable接口以启用其序列化功能。没有方法的接口通常称为标记接口。
管道流
PipedInputStream和PipedOutputStream:输入输出可以直接进行连接,通过结合线程使用。
RandomAccessFile对象
此类的实例支持对随机访问文件的读取和写入。该类不算是IO体系中的子类,而是直接继承自Object。但它是IO包中的成员。因为它具备读和写功能。
RandomAccessFile类内部封装了一个数组,而且通过指针对数组的元素进行操作。可以通过getFilePointer获取指针位置,也可以通过(skipBytes(int x):跳过指定的字节数,seek(int x):调整对象中的指针。)来达到随机访问。
原理:
其实完成读写的原理就是内部封装了字节输入流和输出流。
操作文件的模式:
只读r,读写rw,rws,rwd。
如果模式为只读 r。不会创建文件,会去读取一个已存在文件,如果该文件不存在,则会出现异常。
如果模式rw。操作的文件不存在,会自动创建。如果存在,则不会覆盖。
注意:通过构造函数可以看出,该类只能操作文件。
操作基本数据类型
DataStream对象:DataInputStream与DataOutputStream
writeUTF(String str):以与机器无关方式使用UTF-8修改版编码将一个字符串写入基础输出流。
操作字节数组
ByteArrayInputStream:它包含一个内部缓冲区,该缓冲区包含从流中读取的字节。该类在构造的时候,需要接收数据源,。而且数据源是一个字节数组。
ByteArrayOutputStream:此类实现了一个输出流,其中的数据被写入一个byte数组。该类在构造的时候,不用定义数据目的,因为该对象中已经内部封装了可变长度的字节数组。
注意:因为这两个流对象都操作的数组,并没有使用系统资源。所以,不用进行close关闭。
操作字符数组
CharArrayReader与CharArrayWrite
操作字符串
StringReader与StringWriter
字符编码
由来:
计算机只能识别二进制数据,早期由来是电信号。为了方便应用计算机,让它可以识别各个国家的文字。就将各个国家的文字用数字来表示,并一一对应,形成一张表。这就是编码表。
常见的编码表:
ASCII,ISO8859-1,GB2312,GBK,Unicode,UTF-8。
编码:
字符串变成字节数组。
解码:
字节数组变成字符串。
总结:
File类的出现弥补了流的不足,流对象操作不了文件夹,文件的属性信息。流只能操作数据,而要操作被封装成文件的信息就要用File对象。
在判断文件对象是否是文件或目录时,必须要先判断该文件对象封装的内容是否存在。
递归的表现形式就是函数自身调用自身。
Properties加载的信息一定是键值对,否则没有意义。
ObjectOutputStream和 ObjectInputStream分别与 FileOutputStream和FileInputStream一起使用时,可以为应用程序提供对对象图形的持久存储。
RandomAccessFile对象可以随机写入,也可以指定位置修改。这就可以实现数据的分段写入。而且该对象的构造函数要操作的文件不存在,会自动创建。如果存在则不会覆盖。