Java拥有完善的IO系统,下面就介绍一下,这个部分主要参考<Java核心技术 第10版>.
有时候需要读取外部文件,或者向外部写入文件,其实之前我们就接触过一点IO系统:System中的静态变量out,就是IO流系统中的一员:PrintStream类型的.
IO系统有两个大的分支:字节流与字符流,每个分支都有一个顶级输入父类与顶级输出父类,每个父类都派生出若干子类,子类再派生出子类,构成了整个IO流的大框架.
字节流与字符流
字节流是直接对文件进行操作,而字符流则存在一个缓冲区,流通过缓冲区操作文件.有什么区别呢,我们来看看下面的操作:
1.字节流向磁盘文件而不关闭流(即不对流调用close()):
public static void main(String[] args) throws IOException {
DataOutputStream dos = new DataOutputStream(new FileOutputStream(new File("G:\\IOdir\\test.txt")));
dos.writeUTF("123456789");
}
运行结束后,相应位置会出现一个大小为11字节的txt.(原内容基础上多了两个空白字符)
2.字符流向磁盘写入文件而不关闭流:
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter(new File("G:\\IOdir\\test.txt"));
fw.write("123456789");
}
运行结束后,虽然出现了文件,但是大小为0字节.
3. 字符流向磁盘写入文件并对流调用close():
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter(new File("G:\\IOdir\\test.txt"));
fw.write("123456789");
fw.close();
}
运行结束后,出现了大小为9字节的txt文件,内容为参数内容.
4.字符流写入等于缓冲区大小的数据(我这里是8192字节),且不调用close:
public static void main(String[] args) throws IOException {
File file = new File("G:\\IOdir\\test.txt");
if (file.exists()){
file.delete();
}
FileWriter fw = new FileWriter(file);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 8192; i++) {
sb.append(1);
}
fw.write(sb.toString());
System.out.println(sb.length()); //8192
}
出现了文件,但是大小为0.
5.字符流写入超过缓冲区大小的数据,且不调用close:
public static void main(String[] args) throws IOException {
File file = new File("G:\\IOdir\\test.txt");
FileWriter fw = new FileWriter(file);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 8193; i++) {
sb.append(1);
}
fw.write(sb.toString());
System.out.println(sb.length()); //8193
}
}
运行结束后,出现一个大小为8192字节的文件 ,而StringBuilder的length()返回值为8193,证明有1字节未被写入.
这个缓冲区就是两者性质决定性的差异了,当然这个缓冲区大小也是可以定义的,后面会说到.
File类
别被File的名字骗了,File类不只是可以操作文件,目录也是可以的.
File类的作用是创建一个文件对象,可以是一个目录或者是一个文件,可以对文件或文件夹进行简单操作,如查看是否存在,是否是目录或文件,创建一个文件或目录等,但是对文件夹执行删除时要注意,只能删除空文件夹,只要文件夹内有文件就不能进行操作.
File最常见的位置就是各种IO流的构造器中,比如上面一系列的写文件操作.事实上一切针对外部文件的操作最终都要落实到File上.
File中有几个常量,主要用于不同系统(如Windows和Linux)下的路径分隔符:windows下是\,而Linux等则是/:
public static final char separatorChar = fs.getSeparator();
public static final String separator = "" + separatorChar;
public static final char pathSeparatorChar = fs.getPathSeparator();
public static final String pathSeparator = "" + pathSeparatorChar;
构造器
File(File parent, String child)
父路径parent下新建child字符串的File实例.
File(String pathname)
路径为pathname的File实例.
File(String parent, String child)
父路径字符串parent下新建child字符串的File实例.
File(URI uri)
利用URI创建File实例.
方法
创建与删除
boolean createNewFile():只有该文件不存在的情况下才创建这个文件.
public static void main(String[] args) throws IOException {
File file = new File("G:\\IOdir\\test.txt");
for (int i = 0; i < 2; i++) {
System.out.println(file.createNewFile());
}
}
true
false
第一次由于该文件不存在,所以创建成功,而第二次由于文件已经存在,所以创建失败.
boolean mkdir():创建这个目录,只创建最后一层目录,创建失败则返回false.
boolean mkdirs():创建这个目录,如果父目录不存在也会一并被创建.
测试目录:G:\IOdir,mkdir()未能创建,因为3的父目录2不存在.而mkdirs()则创建成功.
public static void main(String[] args) throws IOException {
File file = new File("G:\\IOdir\\test\\1\\2\\3");
System.out.println(file.mkdir()); //false
System.out.println(file.mkdirs()); //true
}
判断方法
boolean exists()
是否存在
boolean isAbsolute()
是否是绝对路径.
boolean isDirectory()
是否是目录 .
boolean isFile()
是否是文件.
boolean isHidden()
是否是隐藏文件.
测试代码:
public static void main(String[] args) {
File file = new File("G:\\IOdir\\test.txt");
System.out.println("是否存在:" + file.exists()); //true
System.out.println("是否是绝对路径:" + file.isAbsolute()); //true
System.out.println("是否是目录:" + file.isDirectory()); //false
System.out.println("是否是文件:" + file.isFile()); //true
System.out.println("是否是隐藏文件:" + file.isHidden()); //false
}
获取信息方法
String getAbsolutePath()
返回该对象的绝对路径字符串.
String getName()
获取文件名.
String getParent()
获取父路径.
String getPath()
获取路径.
long lastModified()
获取修改时间,数值为距离1970.1.1 0:00:00的毫秒数.
String[] list()
String[] list(FilenameFilter filter) //文件名过滤器
列出文件夹下的文件或文件夹名称.
File[] listFiles()
File[] listFiles(FileFilter filter)
File[] listFiles(FilenameFilter filter)
列出文件夹下的文件或文件夹全路径.
测试代码:
File file = new File("G:\\IOdir\\test.txt");
System.out.println(file.getAbsoluteFile());
System.out.println(file.getAbsolutePath());
System.out.println(file.getParent());
System.out.println(file.getParentFile());
System.out.println(file.getPath());
System.out.println(file.lastModified());
file = new File("G:\\test");
String[] list = file.list();
File[] files = file.listFiles();
System.out.println(Arrays.toString(list));
System.out.println(Arrays.toString(files));
运行结果:
G:\IOdir\test.txt
G:\IOdir\test.txt
G:\IOdir
G:\IOdir
G:\IOdir\test.txt
1549944876752
[1, 2]
[G:\test\1, G:\test\2]
文件操作方法
boolean renameTo(File dest) :重命名为dest.
public static void main(String[] args) {
File file = new File("G:\\IOdir\\test.txt");
System.out.println(file.renameTo(new File("G:\\IOdir\\t.txt"))); //true
}
运行结束后,文件被命名为1.txt.
boolean setExecutable(boolean executable)
boolean setExecutable(boolean executable, boolean ownerOnly)
设置是否可执行,第二个参数指是否只有所有者才持有权限.
boolean setLastModified(long time)
设置最后修改时间
boolean setReadable(boolean readable)
boolean setReadable(boolean readable, boolean ownerOnly)
设置是否可读,第二个参数指是否只有所有者持有权限.
boolean setReadOnly()
设置只读
boolean setWritable(boolean writable)
boolean setWritable(boolean writable, boolean ownerOnly)
设置是否可写/修改,第二个参数指是否只有所有者持有权限.
Path toPath()
返回从此对象路径构造的java.nio.file.Path对象。
URI toURI()
返回为URI对象
递归删除目录
经过上面一系列操作之后,现在想利用delete()删除test目录是不可能的了:
public static void main(String[] args) throws IOException {
File file = new File("G:\\IOdir\\test");
System.out.println(file.delete()); //false
}
然而并没有deleteDir()这样的方法,就只能利用delete().首先来看看求阶乘的例子:
public static void main(String[] args) throws IOException {
for (int i = 1; i < 15; i++) {
System.out.println(multi(i, 1));
}
}
private static String multi(int number, long result) {
if (number == 1) {
System.out.println("阶乘的结果为:" + result);
return "阶乘的结果为:" + result;
}
result *= number;
multi(--number, result);
return "";
}
运行结果为(已经去掉空行):
阶乘的结果为:1
阶乘的结果为:1
阶乘的结果为:2
阶乘的结果为:6
阶乘的结果为:24
.
.
.
阶乘的结果为:6227020800
阶乘的结果为:87178291200
通过不断调用自己来取得下一步结果,删除非空目录也是利用了这个思想:递归:首先判断传进来的file对象是不是目录,如果是目录就先把里面有什么文件夹列出来,返回一个File数组,然后在for循环中对数组中每个元素都调用该方法.最终在输出语句中调用delete(),达成删除文件或空目录的目的.
public static void main(String[] args) throws IOException {
File file = new File("G:\\IOdir\\test");
deleteDir(file);
}
private static void deleteDir(File file){
if (file.isDirectory()){
File[] files = file.listFiles();
for (File f: files) {
deleteDir(f);
}
}
System.out.print(file.delete() + " ");
}
运行结果:
true true true true true true true true true true true true true
打开目录,发现test目录已经被删除.