@lemonguge
2015-07-01T08:06:37.000000Z
字数 8236
阅读 374
I/O
笔者首次接触I/O的时候,查看API后发现类库中提供了如此多的类,当时就感到不知所措了。曾经两次学习到了一半就放弃了,因为实在是记不过来,后来坚持下来把I/O学习完,感受还是很多的。现在对Java I/O系统会进行详细的介绍,希望能对读者有些帮助吧。
“对语言设计人员来说,创建好的输入/输出系统是一项特别困难的任务。”——《Think in Java》
无论是系统、还是语言的设计中I/O的设计都是异常复杂的。面临的最大的挑战一般是如何覆盖所有可能的因素,我们不仅仅要考虑文件、控制台、网络、内存等不同的种类,而且要处理大量的不同的读取方式,如:顺序读取、随机读取、缓存读取、二进制读取、按字符读取、按行读取、按字读取……
在学习Java I/O之前,我们应该学习java.io.File类,笔者认为学习这个类是最容易获得成就感的,同时能对后面的学习起到非常大的作用。
大家第一次看到File类时,我们可能会认为它是一个文件,实际上它要强大的多,它能代表一个特定文件的名称,又能代表一个文件目录的名称。查看API可以发现File类并没有默认的构造器,因为当你创建这个类的对象时就必须初始化FilePath文件路径,此时该对象可以表示一个实际存在的或者不存在的文件或文件目录。实际上,FilePath(文件路径)对这个类说是个更好的名字。
在API中可以发现File类有4个属性,后缀为Char的属性表示为一个字符,pathSeparator和separator属性表示一个字符串,和后缀为Char的属性内容相同,只是表示形式不同。因为字符串的形式更短且更为常用,所有才会出现这两个变体。
public static void showFileProp() {System.out.println(File.pathSeparator);System.out.println(File.separator);System.out.println(File.pathSeparatorChar);System.out.println(File.separatorChar);} /* Output:;\;\*///:~
File.pathSeparator表示路径分隔符,File.separator表示名称分隔符。大家可能会认为,我直接在Windows下使用\进行名称分隔不行吗?当然是可以的。但是在Linux下就不是\了。所以,要想使得我们的代码跨平台,更加健壮,所以,笔者建议大家都采用这两个字符串常量。
创建一个File对象,有两种方式:相对路径和绝对路径。
import java.io.File;import java.io.IOException;public class CreateFile {public static void main(String[] args) throws IOException {creRelFile();creRelDir();}// 在相对路径下创建文件public static void creRelFile() throws IOException {File file = new File("file.txt"); // 创建一个实际不存在的file对象System.out.println(file.createNewFile()); // 在当前项目下创建了一个名为file,后缀为txt的文件file = new File("file.txt"); // 创建一个实际存在的file对象,已表示为一个文件System.out.println(file.createNewFile()); //将创建失败}// 在相对路径下创建目录public static void creRelDir() {File dir = new File("file.txt"); // 创建一个实际存在的file对象,已表示为表示一个文件System.out.println(dir.mkdir()); // 将创建失败dir = new File("dir.txt"); // 创建一个实际不存在的file对象System.out.println(dir.mkdir()); // 在当前项目下创建了一个名为dir.txt的目录}} /* Output:truefalsefalsetrue*///:~
public static void creAbsFile() throws IOException {File file = new File("D:" + File.separator + "file.txt");// 等价于File file = new File("D:\\file.txt");// 在windows下,名称分隔为“\”,由于`java`的正则原因所以需要两个System.out.println(file.createNewFile());file = new File("D:" + File.separator + "io" + File.separator + "file.txt"); // 假设D盘下没有io目录try {System.out.println(file.createNewFile());} catch (IOException e) {System.out.println(e);}} /* Output:truejava.io.IOException: 系统找不到指定的路径。*///:~
在使用绝对路径时,应该时刻注意当前文件路径是否存在。
public static void creAbsDir() throws IOException {File dir = new File("D:" + File.separator + "io" + File.separator + "dir" + File.separator); // 假设D盘下没有io目录System.out.println(dir.mkdir()); // 只能创建单级目录System.out.println(dir.mkdirs()); // 可以创建多级目录File file = new File(dir, "file.txt"); // 通过父路径对象和子路径来创建file对象System.out.println(file.createNewFile()); // 创建文件} /* Output:falsetruetrue*///:~
在D盘下的“io目录”里的“dir目录”中可以找到file.txt文件。
public static void fileCommonMethod() throws IOException {File file = new File("file.txt");if (!file.exists()) // 判断虚拟文件路径是否存在file.createNewFile();System.out.println(file.isFile());System.out.println(file.isDirectory()); // 判断是否表示一个目录System.out.println(file.isAbsolute()); // 测试此抽象路径名是否为绝对路径名。System.out.println(file.isHidden()); // 判断文件是否为隐藏System.out.println(file.getName());System.out.println(file.canExecute());// 是否可执行System.out.println(file.canRead());// 是否可读System.out.println(file.canWrite());// 是否可写System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(file.lastModified())));// 最近修改时间// 无符号右移30位即/1024/1024/1024,查看以G为单位的存储空间System.out.println(Long.toString(file.getFreeSpace() >>> 30) + "G");// 当前分区的可用空间,即D盘的可用容量System.out.println(Long.toString(file.getTotalSpace() >>> 30) + "G");// D盘总容量System.out.println(Long.toString(file.getUsableSpace() >>> 30) + "G");// //D盘可用于虚拟机的空间System.out.println(file.getPath());// 创建File对象中写什么便输出什么System.out.println(file.getParent());System.out.println(file.getAbsolutePath());System.out.println(new File(file.getAbsolutePath()).getName());System.out.println(new File(file.getAbsolutePath()).getPath());System.out.println(new File(file.getAbsolutePath()).getParent());System.out.println(new File(new File(file.getAbsolutePath()).getParent(),"file.txt").getPath());} /* Output:truefalsefalsefalsefile.txttruetruetrue2015-06-13 12:15:55144G299G144Gfile.txtnullG:\itcast_wordspace\io\file.txtfile.txtG:\itcast_wordspace\io\file.txtG:\itcast_wordspace\ioG:\itcast_wordspace\io\file.txt*///:~
public static void listRootFiles() throws IOException {// 列出可用的文件系统根。File[] files = File.listRoots(); // 在Windows环境下,驱动器也会被提供根目录System.out.println(files.length);System.out.println("-------");for (File file : files) {System.out.println(file + "=" + String.valueOf(file.getFreeSpace() >>> 30) + "G");File sys = new File(file, File.separator);String name = sys.getName();System.out.println(name); // 每个分区和驱动器的名字虽然无法显示且长度为0,但不为null,也不为""。// System.out.println(name.length()); // 0// System.out.println(name==""); // false// System.out.println(name==null); // falseif (sys.listFiles() != null)for (File sf : sys.listFiles()) // 当前分区的所有目录System.out.println(sf.getName());System.out.println("-------");}} /* Output:5-------C:\=41G$Recycle.Bincache_index.dbCFLogDocuments and Settings... // 太多不全部显示-------D:\=275G$RECYCLE.BINBaiduYunDownloadDMDownLoad...-------E:\=0G // 此为一个驱动器-------G:\=144G$RECYCLE.BINCWIntelliJ_Project...-------I:\=98G$RECYCLE.BINSystem Volume Informationvideo...-------*///:~
public static void listFiles() {File file = new File("D:"+File.separator);String[] fileStrs = file.list(); // 指定此抽象路径名表示的目录中的文件和目录。for(String fileStr : fileStrs)System.out.println(fileStr);} /* Output:$RECYCLE.BINBaiduYunDownloaddir.txtfile.txtoraysl.statusProgram Files... // 太多不全部显示*///:~
FilenameFilter接口中只有一个方法:boolean accept(File dir, String name),该方法的作用是测试指定文件是否应该包含在某一文件列表中。
public static void filenameFilter() {File file = new File("D:"+File.separator);String[] fileNames = file.list(new FilenameFilter(){@Overridepublic boolean accept(File dir, String name) {return name.endsWith(".txt");}});System.out.println(Arrays.toString(fileNames));for(String fileName : fileNames)System.out.println(fileName+" "+(new File(file,fileName).isDirectory()?"is a Dir":"is a File"));} /* Output:[dir.txt, file.txt]dir.txt is a Dirfile.txt is a File*///:~
FileFilter接口中也只有一个方法:boolean accept(File pathname),该方法的作用是测试指定抽象路径名是否应该包含在某个路径名列表中。
public static void fileFilter() {File file = new File("D:" + File.separator);File[] files = file.listFiles(new FileFilter() {@Overridepublic boolean accept(File pathname) {return !pathname.isDirectory(); // 过滤掉所有的目录}});System.out.println(Arrays.toString(files));} /* Output:[D:\file.txt, D:\oraysl.status]*///:~
该方法表示的是重命名一个文件或目录、移动一个文件。
// 重命名的情况public static void renameToRn() throws IOException {File dir = new File("D:" + File.separator);File dest = new File(dir, "newdir.txt");System.out.println(dest.exists());File file = new File(dir, "dir.txt");if(!file.exists())file.mkdir();System.out.println(file.renameTo(dest)); // 重命名目录System.out.println(file.exists());System.out.println(dest.exists());} /* Output:falsetruefalsetrue*///:~
public static void renameToMv() {File file = new File("D:" + File.separator+"file.txt"); // 文件存在File dest = new File("G:" + File.separator+"newfile.txt");System.out.println(file.exists());System.out.println(dest.exists());System.out.println(file.renameTo(dest));System.out.println(file.exists());System.out.println(dest.exists());System.out.println("---------");file = new File("D:" + File.separator+"dir.txt"); // 目录存在dest = new File("C:" + File.separator+"newfile.txt");System.out.println(file.exists());System.out.println(dest.exists());System.out.println(file.renameTo(dest));} /* Output:truefalsetruefalsetrue---------truefalsefalse*///:~
删除此抽象路径名表示的文件或目录。如果此路径名表示一个目录,则该目录必须为空才能删除。
public static void delete() {File dir = new File("D:" + File.separator + "a" + File.separator + "b" + File.separator + "c");System.out.println(dir.mkdirs()); // 创建多级目录System.out.println(dir.getName()); // 该虚拟文件路径表示为一个c目录System.out.println(dir.delete()); // 仅仅删除了c目录!} /* Output:truectrue*///:~
public static void delete() throws IOException {File dir = new File("D:" + File.separator + "a" + File.separator + "b" + File.separator + "c");System.out.println(dir.mkdirs()); // 创建多级目录File file = new File(dir, "file.txt");System.out.println(file.createNewFile());System.out.println(dir.delete()); // 目录中有文件,删除失败} /* Output:truetruefalse*///:~
public static void removeDir(File dir) {File[] files = dir.listFiles();for(File file : files){if(file.isDirectory()){removeDir(file);}else{System.out.println(file+":"+file.delete());}}System.out.println(dir+":"+dir.delete());}