欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

详解Java中的File文件类以及FileDescriptor文件描述类

程序员文章站 2024-03-13 08:08:21
file file 是“文件”和“目录路径名”的抽象表示形式。 file 直接继承于object,实现了serializable接口和comparable接口。实现se...

file

file 是“文件”和“目录路径名”的抽象表示形式。
file 直接继承于object,实现了serializable接口和comparable接口。实现serializable接口,意味着file对象支持序列化操作。而实现comparable接口,意味着file对象之间可以比较大小;file能直接被存储在有序集合(如treeset、treemap中)。
1. 新建目录的常用方法
方法1:根据相对路径新建目录。
示例代码如下(在当前路径下新建目录“dir”):

file dir = new file("dir");
dir.mkdir();

方法2:根据绝对路径新建目录。
示例代码如下(新建目录“/home/skywang/dir”):

file dir = new file("/home/skywang/dir");
dir.mkdirs();

说明:上面是在linux系统下新建目录“/home/skywang/dir”的源码。在windows下面,若要新建目录“d:/dir”,源码如下:

file dir = new file("d:/dir");
dir.mkdir();

方法3

uri uri = new uri("file:/home/skywang/dir"); 
file dir = new file(uri);
sub.mkdir();

说明: 和“方法2”类似,只不过“方法2”中传入的是完整路径,而“方法3”中传入的是完整路径对应uri。
2. 新建子目录的几种常用方法
例如,我们想要在当前目录的子目录“dir”下,再新建一个子目录。有一下几种方法:
方法1

file sub1 = new file("dir", "sub1");
sub1.mkdir();

说明:上面的方法作用是,在当前目录下 "dir/sub1"。它能正常运行的前提是“sub1”的父目录“dir”已经存在!
方法2

file sub2 = new file(dir, "sub2");
sub2.mkdir();

说明:上面的方法作用是,在当前目录下 "dir/sub2"。它能正常运行的前提是“sub2”的父目录“dir”已经存在!
方法3

file sub3 = new file("dir/sub3");
sub3.mkdirs();

说明:上面的方法作用是,在当前目录下 "dir/sub3"。它不需要dir已经存在,也能正常运行;若“sub3”的父母路不存在,mkdirs()方法会自动创建父目录。
方法4

file sub4 = new file("/home/skywang/dir/sub4");
sub4.mkdirs();

说明:上面的方法作用是,新建目录"/home/skywang/dir/sub3"。它不需要dir已经存在,也能正常运行;若“sub4”的父母路不存在,mkdirs()方法会自动创建父目录。
方法5

uri uri = new uri("file:/home/skywang/dir/sub5"); 
file sub5 = new file(uri);
sub5.mkdirs();

说明: 和“方法4”类似,只不过“方法4”中传入的是完整路径,而“方法5”中传入的是完整路径对应uri。
3. 新建文件的几种常用方法
例如,我们想要在当前目录的子目录“dir”下,新建一个文件。有一下几种方法
方法1

try {
  file dir = new file("dir");  // 获取目录“dir”对应的file对象
  file file1 = new file(dir, "file1.txt");
  file1.createnewfile();
} catch (ioexception e) {
  e.printstacktrace();
}

说明:上面代码作用是,在“dir”目录(相对路径)下新建文件“file1.txt”。
方法2

try {
  file file2 = new file("dir", "file2.txt");
  file2.createnewfile();
} catch (ioexception e) {
  e.printstacktrace();
}

说明:上面代码作用是,在“dir”目录(相对路径)下新建文件“file2.txt”。
方法3

try {
  file file3 = new file("/home/skywang/dir/file3.txt");
  file3.createnewfile();
} catch (ioexception e) {
  e.printstacktrace();
}

说明:上面代码作用是,下新建文件“/home/skywang/dir/file3.txt”(绝对路径)。这是在linux下根据绝对路径的方法,在windows下可以通过以下代码新建文件"d:/dir/file4.txt"。

try {
  file file3 = new file("d:/dir/file4.txt");
  file3.createnewfile();
} catch (ioexception e) {
  e.printstacktrace();
}

方法4

try {
  uri uri = new uri("file:/home/skywang/dir/file4.txt"); 
  file file4 = new file(uri);
  file4.createnewfile();
} catch (ioexception e) {
  e.printstacktrace();
}

说明:
和“方法3”类似,只不过“方法3”中传入的是完整路径,而“方法4”中传入的是完整路径对应uri。
4. file api使用示例
关于file中api的详细用法,参考示例代码(filetest.java):

import java.io.file;
import java.io.ioexception;
import java.net.uri;
import java.util.calendar;
import java.text.simpledateformat;

public class filetest {

  public static void main(string[] args) {
    testfilestaticfields() ;
  testfiledirapis() ;
  }

  public static void testfilestaticfields() {
    // 打印 路径分隔符":"
    system.out.printf("file.pathseparator=\"%s\"\n", file.pathseparator);
    // 打印 路径分隔符':'
    system.out.printf("file.pathseparatorchar=\"%c\"\n", file.pathseparatorchar);
    // 打印 分隔符"/"
    system.out.printf("file.separator=\"%s\"\n", file.separator);
    // 打印 分隔符'/'
    system.out.printf("file.separatorchar=\"%c\"\n", file.separatorchar);
  }

  public static void testfiledirapis() {
    try {
    // 新建目录 "dir"
    file dir = new file("dir");
    dir.mkdir();

    // 方法1:新建目录 "dir/sub1"。父目录“dir”必须已经存在!
    file sub1 = new file("dir", "sub1");
    sub1.mkdir();
    // 方法2:新建目录 "dir/sub2"。父目录“dir”必须已经存在!
    file sub2 = new file(dir, "sub2");
    sub2.mkdir();
    // 方法3:新建目录 "dir/sub3"。mkdirs()会自动创建不存在的父目录。
    file sub3 = new file("dir/sub3");
    sub3.mkdirs();
    // 方法4:新建目录 "dir/sub4"。根据“绝对路径”创建,前面3个方法都是根据“相对路径”创建。
    string dirpath = dir.getabsolutepath();  // 获取“dir”的绝对路径
    string sub4abspath = dirpath + file.separator + "sub4";  // file.separator是分隔符"/"
    file sub4 = new file(sub4abspath);
    sub4.mkdirs();
    // 方法5:新建目录 "dir/sub5"。根据uri
    string uri_sub5_path = "file:"+ dirpath + file.separator + "sub5";
    uri uri_sub5 = new uri(uri_sub5_path); 
    file sub5 = new file(uri_sub5);
    sub5.mkdirs();

    // 方法1:新建文件 "dir/l1_normal.txt"
    file l1_normal = new file(dir, "l1_normal.txt");
    l1_normal.createnewfile();
    // 方法2:新建文件 "dir/.l1_hide.txt"。
    file l1_hide = new file("dir", ".l1_hide.txt"); // 在linux中, "."开头的文件是隐藏文件。
    l1_hide.createnewfile();
    // 方法3:新建文件 "dir/l1_abs.txt"。
    string dirabspah = dir.getabsolutepath();  // 获取dir的绝对路径
    string l1_abs_path = dirabspah+file.separator+"l1_abs.txt";
    file l1_abs = new file(l1_abs_path);
    l1_abs.createnewfile();
    //system.out.printf("l1_abs_path=%s\n", l1_abs_path);
    //system.out.printf("l1_abs path=%s\n", l1_abs.getabsolutepath());
    // 方法4:新建文件 "dir/l1_uri.txt"。根据uri新建文件
    string uri_path = "file:"+ dirabspah + file.separator + "l1_uri.txt";
    uri uri_l1 = new uri(uri_path); 
    //system.out.printf("uri_l1=%s\n", l1_abs.getabsolutepath());
    file l1_uri = new file(uri_l1); 
    l1_uri.createnewfile();

    // 新建文件 "dir/sub/s1_normal"
    file s1_normal = new file(sub1, "s1_normal.txt");
    s1_normal.createnewfile();

    system.out.printf("%30s = %s\n", "s1_normal.exists()", s1_normal.exists());
    system.out.printf("%30s = %s\n", "s1_normal.getname()", s1_normal.getname());
    system.out.printf("%30s = %s\n", "s1_normal.getparent()", s1_normal.getparent());
    system.out.printf("%30s = %s\n", "s1_normal.getpath()", s1_normal.getpath());
    system.out.printf("%30s = %s\n", "s1_normal.getabsolutepath()", s1_normal.getabsolutepath());
    system.out.printf("%30s = %s\n", "s1_normal.getcanonicalpath()", s1_normal.getcanonicalpath());
    system.out.printf("%30s = %s is \"%s\"\n", "s1_normal.lastmodified()", s1_normal.lastmodified(), getmodifytime(s1_normal.lastmodified()));
    system.out.printf("%30s = %s\n", "s1_normal.touri()", s1_normal.touri());


    // 列出“dir”目录下的“文件”和“文件夹”。
    // 注意:dir.listfiles()只会遍历目录dir,而不会遍历dir的子目录!
    system.out.println("---- list files and folders ----");
    file[] fs = dir.listfiles();
    for (file f:fs) {
      string fname = f.getname();
      string absstr = f.isabsolute() ? "[absolute]" : "";
      string hidstr = f.ishidden() ? "[hidden]" : "";
      string dirstr = f.isdirectory() ? "[directory]" : "";
      string filestr = f.isfile() ? "[file]" : "";

      system.out.printf("%-30s %s%s%s%s\n", fname, filestr, dirstr, absstr, hidstr);
    }

    } catch (exception e) {
      e.printstacktrace();
    }
  }

  private static string getmodifytime(long millis) {
    // 获取calendar对象
    calendar cal = calendar.getinstance();
    // 设置时间为 millis
    cal.settimeinmillis(millis);
    // 获取格式化对象,它会按照"yyyy-mm-dd hh:mm:ss"格式化日期
    simpledateformat sdf = new simpledateformat("yyyy-mm-dd hh:mm:ss");
    //system.out.printf("time %s\n", str);
    return sdf.format(cal.gettime()); 
  }

}

运行结果(在ubuntu 12.04系统下的运行结果,而不是windows!):

file.pathseparator=":"
file.pathseparatorchar=":"
file.separator="/"
file.separatorchar="/"
      s1_normal.exists() = true
      s1_normal.getname() = s1_normal.txt
     s1_normal.getparent() = dir/sub1
      s1_normal.getpath() = dir/sub1/s1_normal.txt
  s1_normal.getabsolutepath() = /home/skywang/wind_talker/workout/java/skywang/io/io/src/file/dir/sub1/s1_normal.txt
 s1_normal.getcanonicalpath() = /home/skywang/wind_talker/workout/java/skywang/io/io/src/file/dir/sub1/s1_normal.txt
   s1_normal.lastmodified() = 1381730064000 is "2013-10-14 13:54:24"
       s1_normal.touri() = file:/home/skywang/wind_talker/workout/java/skywang/io/io/src/file/dir/sub1/s1_normal.txt
---- list files and folders ----
l1_uri.txt           [file]
sub1              [directory]
l1_abs.txt           [file]
sub5              [directory]
sub4              [directory]
.l1_hide.txt          [file][hidden]
sub3              [directory]
sub2              [directory]
l1_normal.txt          [file]

结果说明:运行程序,会在源文件所在的目录新建目录"dir"及其子目录和子文件。如下图:

详解Java中的File文件类以及FileDescriptor文件描述类

filedescriptor

filedescriptor 是“文件描述符”。
filedescriptor 可以被用来表示开放文件、开放套接字等。
以filedescriptor表示文件来说:当filedescriptor表示某文件时,我们可以通俗的将filedescriptor看成是该文件。但是,我们不能直接通过filedescriptor对该文件进行操作;若需要通过filedescriptor对该文件进行操作,则需要新创建filedescriptor对应的fileoutputstream,再对文件进行操作。
in, out, err介绍
(1) in -- 标准输入(键盘)的描述符
(2) out -- 标准输出(屏幕)的描述符
(3) err -- 标准错误输出(屏幕)的描述符
它们3个的原理和用法都类似,下面我们通过out来进行深入研究。
1.1 out 的作用和原理
out是标准输出(屏幕)的描述符。但是它有什么作用呢?
我们可以通俗理解,out就代表了标准输出(屏幕)。若我们要输出信息到屏幕上,即可通过out来进行操作;但是,out又没有提供输出信息到屏幕的接口(因为out本质是filedescriptor对象,而filedescriptor没有输出接口)。怎么办呢?
很简单,我们创建out对应的“输出流对象”,然后通过“输出流”的write()等输出接口就可以将信息输出到屏幕上。如下代码:

try {
  fileoutputstream out = new fileoutputstream(filedescriptor.out);
  out.write('a');
  out.close();
} catch (ioexception e) {
}

执行上面的程序,会在屏幕上输出字母'a'。
为了方便我们操作,java早已为我们封装好了“能方便的在屏幕上输出信息的接口”:通过system.out,我们能方便的输出信息到屏幕上。
因此,我们可以等价的将上面的程序转换为如下代码:

system.out.print('a');

下面讲讲上面两段代码的原理
查看看out的定义。它的定义在filedescriptor.java中,相关源码如下:

public final class filedescriptor {

  private int fd;

  public static final filedescriptor out = new filedescriptor(1);

  private filedescriptor(int fd) {
    this.fd = fd;
    usecount = new atomicinteger();
  }

  ...
}

从中,可以看出
(1) out就是一个filedescriptor对象。它是通过构造函数filedescriptor(int fd)创建的。
(2) filedescriptor(int fd)的操作:就是给fd对象(int类型)赋值,并新建一个使用计数变量usecount。
fd对象是非常重要的一个变量,“fd=1”就代表了“标准输出”,“fd=0”就代表了“标准输入”,“fd=2”就代表了“标准错误输出”。

fileoutputstream out = new fileoutputstream(filedescriptor.out);

 就是利用构造函数fileoutputstream(filedescriptor fdobj)来创建“filed.out对应的fileoutputstream对象”。
关于system.out是如何定义的。可以参考"深入了解system.out.println("hello world") "
通过上面的学习,我们知道,我们可以自定义标准的文件描述符[即,in(标准输入),out(标准输出),err(标准错误输出)]的流,从而完成输入/输出功能;但是,java已经为我们封装好了相应的接口,即我们可以更方便的system.in, system.out, system.err去使用它们。
另外,我们也可以自定义“文件”、“socket”等的文件描述符,进而对它们进行操作。参考下面示例代码中的testwrite(), testread()等接口。
2. 示例代码
源码如下(filedescriptortest.java):

import java.io.printstream;
import java.io.filedescriptor;
import java.io.fileinputstream;
import java.io.fileoutputstream;
import java.io.ioexception;

public class filedescriptortest {

  private static final string filename = "file.txt";
  private static final string outtext = "hi filedescriptor";
  public static void main(string[] args) {
    testwrite();
    testread();

    teststandfd() ;
    //system.out.println(outtext);
  }

  /**
   * filedescriptor.out 的测试程序
   *
   * 该程序的效果 等价于 system.out.println(outtext);
   */
  private static void teststandfd() {
    // 创建filedescriptor.out 对应的printstream
    printstream out = new printstream(
        new fileoutputstream(filedescriptor.out));
    // 在屏幕上输出“hi filedescriptor”
    out.println(outtext);
    out.close();
  }

  /**
   * filedescriptor写入示例程序
   * 
   * (1) 为了说明,"通过文件名创建fileoutputstream"与“通过文件描述符创建fileoutputstream”对象是等效的
   * (2) 该程序会在“该源文件”所在目录新建文件"file.txt",并且文件内容是"aa"。
   */
  private static void testwrite() {
    try {
      // 新建文件“file.txt”对应的fileoutputstream对象
      fileoutputstream out1 = new fileoutputstream(filename);
      // 获取文件“file.txt”对应的“文件描述符”
      filedescriptor fdout = out1.getfd();
      // 根据“文件描述符”创建“fileoutputstream”对象
      fileoutputstream out2 = new fileoutputstream(fdout);

      out1.write('a');  // 通过out1向“file.txt”中写入'a'
      out2.write('a');  // 通过out2向“file.txt”中写入'a'

      if (fdout!=null)
        system.out.printf("fdout(%s) is %s\n",fdout, fdout.valid());

      out1.close();
      out2.close();

    } catch(ioexception e) {
      e.printstacktrace();
    }
  }

  /**
   * filedescriptor读取示例程序
   *
   * 为了说明,"通过文件名创建fileinputstream"与“通过文件描述符创建fileinputstream”对象是等效的
   */
  private static void testread() {
    try {
      // 新建文件“file.txt”对应的fileinputstream对象
      fileinputstream in1 = new fileinputstream(filename);
      // 获取文件“file.txt”对应的“文件描述符”
      filedescriptor fdin = in1.getfd();
      // 根据“文件描述符”创建“fileinputstream”对象
      fileinputstream in2 = new fileinputstream(fdin);

      system.out.println("in1.read():"+(char)in1.read());
      system.out.println("in2.read():"+(char)in2.read());

      if (fdin!=null)
        system.out.printf("fdin(%s) is %s\n", fdin, fdin.valid());

      in1.close();
      in2.close();
    } catch(ioexception e) {
      e.printstacktrace();
    }
  }
}

运行结果:

fdout(java.io.filedescriptor@2b820dda) is true
in1.read():a
in2.read():a
fdin(java.io.filedescriptor@675b7986) is true
hi filedescriptor