一. File类

1. 创建File对象

创建File对象可使用new File()方法实现。具体参数如下:

方法 描述
File(File dir, String name) File对象类型的目录路径,name为文件名或目录名。
File(String path) path为新File对象的路径。
File(String dirPath, String name) dirPath为指定的文件路径,name为文件名或目录名。
File(URI uri) 使用URI指定路径来创建新的File对象。

2. File对象的方法

1. File对象判断方法

方法 描述
boolean canExecute() 判断文件或目录是否可执行。
boolean canRead() 判断文件或目录是否可读。
boolean canWrite() 判断文件或目录是否可写。
boolean equals(Object obj) 判断obj和调用的对象是否相同。
boolean exists() 判断文件或目录是否存在。
boolean isAbsolute() 判断当前文件路径是否为绝对路径。
boolean isDirectory() 判断File对象是否是文件夹。
boolean isFile() 判断File对象是否是文件。
boolean isHidden() 判断是否为操作系统定义的隐藏文件。

2. File对象属性返回方法

方法 描述
File getAbsoluteFile() 返回一个新的文件,该文件的绝对路径是调用的File的路径。
String getAbsolutePath() 返回该文件的绝对路径。
long getFreeSpace() 返回所在分区上剩余的字节数量,包括当前File的路径。
String getName() 获得文件名或文件名。
String getParent() 获得文件或文件夹的父目录名。
String getPath() 获取相对路径。
long getTotalSpace() 返回分区的总字节大小。
long getUsableSpace() 返回分区可用字节的大小。
long lastModified() 返回最后一次修改该文件的时间,以毫秒计算,从1970年1月1日开始算。
long length() 返回文件的长度,单位为字节。
String toString() 返回一个对象的字符串表示。
URI toURI() 返回一个文件的URI。

3. File对象属性设置方法

方法 描述
boolean renameTo(File newPath) 修改文件夹名和文件名。
boolean setLastModified(long time) 设置最后一次修改该文件的时间,以毫秒计算,从1970年1月1日开始算。
boolean setReadOnly() 设置文件只有读权限。
boolean setReadable(boolean readable[, boolean ownerOnly]) 设置文件的读状态。
boolean setWritable([boolean writable,] boolean ownerOnly]) 设置文件的写状态。

4. File对象的增删查改

方法 描述
boolean createNewFile() 创建文件或文件夹。
boolean delete() 删除文件夹或文件。
File[] listFiles() 列出文件夹下的所有文件和文件夹名。
boolean mkdir() 创建一个文件夹。当父目录存在才能成功创建。
boolean mkdirs() 创建一个文件夹。当父目录不存在时,则创建父目录。

二. 输入流与输出流进行读写操作

java.io包中包含了流式I/O所需要的所有类。在java.io包中有四个基本类:InputStream、OutputStream及Reader、Writer类,它们分别处理字节流和字符流。

基本数据流的I/O类如下:

输入/输出 字节流 字符流
输入流 Inputstream Reader
输出流 OutputStream Writer

Java中其他多种多样变化的流均是由它们派生出来的:

此处输入图片的描述

此处输入图片的描述

此处输入图片的描述

此处输入图片的描述

图1 . 图片来源:http://my.oschina.net/weiweiqiao/blog/498961

Java中IO流的体系结构如下图:

此处输入图片的描述

图2 . 图片来源:http://blog.csdn.net/hguisu/article/details/7418161

本文主要关注文件的读写,下面将对File文件流进行详细的介绍。对文件进行读、写操作的类有:FileReader、FileWriter、FileInputStream、FileOutputStream。

1 . 输入流 FileInputStream

作用:以文件作为数据输入源的数据流。从文件读数据到内存。

(1)创建FileInputStream对象的方法有:

  • FileInputStream(File file)
  • FileInputStream(FileDescriptor fd)
  • FileInputStream(String path)

(2)从输入流中读取数据的方法:

方法 描述
int read( ) 读取一个字节,返回值为所读的字节。
int read(byte[] buffer, int byteOffset, int byteCount) 读取byteCount个字节,放置到以下标byteOffset开始字节数组buffer中,返回值为实际读取的字节的数量
int available() 返回值为流中尚未读取的字节的数量
long skip(long byteCount) 读指针跳过byteCount个字节不读,返回值为实际跳过的字节数量。

(3)关闭输入流:

方法 描述
void close() 流操作完毕后必须关闭。否则可能导致内存泄漏。

官方的示例如下:

   File file = ...;
   InputStream in = null;
   try {
     in = new BufferedInputStream(new FileInputStream(file));
     ...
    finally {
     if (in != null) {
       in.close();
     }
   }
 }

2.输出流 OutputStream

作用:用来处理以文件作为数据输出目的数据流。从内存区读数据入文件。

(1)创建FileOutputStream对象的方法有:

  • FileOutputStream(File file)
  • FileOutputStream(File file, boolean append) // 当第二个参数为true时,表示在原文件中追加输出的内容
  • FileOutputStream(FileDescriptor fd)
  • FileOutputStream(String path)
  • FileOutputStream(String path, boolean append)

(2)从输出流中输出数据的方法:

方法 描述
void write(int oneByte) 往流中写一个字节oneByte。
void write(byte[] buffer, int byteOffset, int byteCount) 字节数组buffer中从下标byteOffset开始,长度为byteCount的字节写入输出流中。

(3)关闭输出流:

方法 描述
void close( ) 流操作完毕后必须关闭。否则可能导致内存泄漏。

官方的示例如下:

File file = ...
OutputStream out = null;
try {
    out = new BufferedOutputStream(new FileOutputStream(file));
    ...
    finally {
        if (out != null) {
            out.close();
        }
    }
}

3. FileReader

作用:主要用来读取字符文件。

FileReader类的实例的方法继承自java.io.InputStreamReader、java.io.Reader、java.lang.Object、java.lang.Readable、java.io.Closeable、java.lang.AutoCloseable。

(1)创建FileReader对象的方法有:

  • FileReader(File file)
  • FileReader(FileDescriptor fd)
  • FileReader(String filename)

(2)读取字符文件的主要方法有:

方法 描述
int read() 读取单个字符。返回作为整数读取的字符,如果已达到流末尾,则返回-1。
int read(char []charBuffer) 将字符读入charBuffer数组。返回读取的字符数。如果已经到达尾部,则返回-1。

(3)关闭输出流:

方法 描述
void close() 关闭此流对象,并释放与之关联的所有资源。

4. FileWriter

作用:与FileOutputStream对应。将字符类型数据写入文件,使用缺省字符编码和缓冲器大小。

(1)创建FileWriter对象的方法有:

  • FileWriter(File file)
  • FileWriter(File file, boolean append)
  • FileWriter(FileDescriptor fd)
  • FileWriter(String filename)
  • FileWriter(String filename, boolean append)

FileWriter类的实例的方法继承自java.io.OutputStreamWriter、java.io.Writer、java.lang.Object、java.lang.Appendable、java.io.Closeable、java.io.Flushable、java.lang.AutoCloseable

(2)将字符类型数据写入文件的主要方法有:

方法 描述
void write(int oneByte) 往流中写一个字节oneByte。
void write(byte[] buffer, int byteOffset, int byteCount) 字节数组buffer中从下标byteOffset开始,长度为byteCount的字节写入输出流中。
viod flush() 刷新该流中的缓冲。将缓冲区中的字符数据保存到目的文件中去。

(3)关闭字符写入流:

方法 描述
void close() 关闭此流对象,并释放与之关联的所有资源。
FileReader fr = null;
FileWriter fw = null;
try {
    fr = new FileReader("my.txt");
    fw = new FileWriter("you.txt");

    char[] buf = new char[1024];
    int len = 0;
    while((len = fr.read(buf)) != -1){
        // 写入字符
        fw.write(buf, 0, len);                
    }

 } catch (Exception e) {
    System.out.println(e.toString());
} finally {
    if (fr != null) {
        try {
            // 关闭字符输出流
            fr.close();
        } catch (Exception e2) {
            throw new RuntimeException("关闭失败!");
        }
    }
    if (fw != null) {
        try {
            // 关闭字符写入流
            fw.close();
        } catch (IOException e) {
            throw new RuntimeException("关闭失败!");
        }
    }
}

关于Java的输入输出流可参考:《Java输入输出流

三. I/O文件流访问内部存储上的文件

Java提供了一套完整的I/O流体系,包括FileInputStream、FileOutputStream等,通过这些I/O流可以非常方便地访问磁盘上的文件内容。

Context提供了如下两个方法来打开本应用程序的数据文件的文件I/O流:

  • FileInputStream openFileInput(String name):打开应用程序的数据文件下的name文件对应的输入流;
  • FileOutputStream openFileOutput(String name, int mode):打开应用程序的数据文件下的name文件对应的输出流。

其中,openFileOutput(String name, int mode)中的mode参数表示打开文件的模式,可取的值如下:

  • Context.MODE_PRIVATE:该文件只能被本应用程序访问。如果写入,则覆盖原文件;
  • Context.MODE_APPEND:该文件以追加方式打开文件,只能被本应用程序访问;
  • Context.MODE_WORLD_READABLE:该文件的内容可以被其他程序读取;
  • Context.MODE__WORLD_WRITEABLE:该文件的内容可以被其他程序读写。如果写入,则覆盖原文件。

注意,如果希望文件模式叠加,则可以使用加号连接,如 " Context.MODE_APPEND + Context.MODE_WORLD_WRITEABLE "来 表示其他应用以追加方式读写文件。

此外,Context还提供了如下几个方法来访问应用程序的数据文件夹:

方法 描述
File getFilesDir() 返回本应用程序的数据文件夹的绝对路径。在这里获取到的是"/data/data/<包名>/files/"目录,返回File对象。
File getCacheDir() 返回本应用程序在外部存储的存储目录。用于获取"/cache/"目录,返回File对象。
File getExternalCacheDir() 返回本应用程序默认的缓存文件存放路径。用于获取"/data/data/<包名>/cache/"目录,返回File对象。
String[] fileList() 返回本应用程序的数据文件夹的全部文件。
boolean deleteFile(String) 删除本应用程序的数据文件夹下的指定文件。
File getDatabasePath(String name) 返回以openOrCreateDatabase(String, int, SQLiteDatabase.CursorFactory)方法创建的数据库的绝对路径。
File getFileStreamPath(String name) 返回以openFileOutput(String, int)方法创建的文件的绝对路径。

上面表格的方法都是通过上下文对象Context获取的,新创建的文件和目录都属于本应用程序所有。只要应用程序被卸载,这些文件或目录都会被清空。

四. File存储实例

1 . 写入并保存文件内容:

// 写入并保存文件内容
public void writeFiles(String content, String fileName) {
    // 初始化文件输出流
    FileOutputStream fileOutputStream = null;
    try {
        // 以追加模式打开文件输出流
        fileOutputStream = openFileOutput(fileName, MODE_APPEND);
        fileOutputStream.write(content.getBytes());
        // 关闭文件输出流
        fileOutputStream.close();

    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }catch (IOException e) {
        e.printStackTrace();
    }
}

2 . 读取文件内容:

// 读取文件内容
public String readFiles(String fileName) {
    // 定义文件内容字符串
    String content = null;
    // 文件输入流
    FileInputStream fileInputStream = null;
    try {
        // 打开文件输入流
        fileInputStream = openFileInput(fileName);
        // 将文件输入流存放在ByteArrayOutputStream
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        // 定义每次读取一个字节
        byte[] buffer = new byte[1024];
        // 定义每次读取的字节长度
        int len = 0;
        // 读取文件输入流的内容,并存入ByteArrayOutputStream中
        while ((len = fileInputStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, len);
        }
        // 将文件输入流数据以字符串的形式存放
        content = outputStream.toString();
        // 关闭文件输入流
        fileInputStream.close();
        // 关闭ByteArrayOutputStream
        outputStream.close();

    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

    // 返回文件内容
    return content;
}

3 . 页面展示逻辑:

private EditText dataInput;
private Button dataShowBtn;
private TextView dataShowText;
private String fileName = "test.txt";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    dataInput = (EditText) findViewById(R.id.data_input);
    dataShowBtn = (Button) findViewById(R.id.data_show_btn);
    dataShowText = (TextView) findViewById(R.id.data_show_text);

    // 按钮点击,则将EditText中的内容写入文件中,并展示出来
    dataShowBtn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // 定义存放写入的文件名
            // 将EditorText中的输入内容以追加模式写入文件中
            writeFiles(dataInput.getText().toString(), fileName);
            // 输出文件内容,并展示
            dataShowText.setText(readFiles(fileName));
        }
    });
}

4 . activity_main.xml布局文件如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:showIn="@layout/activity_main"
    android:orientation="vertical">
    <EditText
        android:id="@+id/data_input"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:lines="4"
        android:text=""/>
    <Button
        android:id="@+id/data_show_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Write In And Read"/>
    <TextView
        android:id="@+id/data_show_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>

5 . 可在DDMS中查看到新建的text文件,文件路径为:" /data/data/<包名>/files/test.txt "。

6 . 实例效果图如下:

此处输入图片的描述

五. 读写SD卡上的文件

当程序通过Context的openFileInputStream、OpenFileOutputStream来打开文件输入流、输出流时,程序所打开的都是应用程序的数据文件夹里的文件。但这样存储的文件大小比较有限,因为手机内置的存储空间不大。而SD卡可大大地扩充收的存储能力。

为了更好地存取应用程序的大文件数据,应用程序需要读写SD卡上的文件。

读、写SD卡上的文件的步骤如下:

第1步:在AndroidMainfest.xml文件中添加读写SD的权限

<!-- 在SD卡中创建与删除文件的权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<!-- 向SD卡中写入数据的权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

第2步:判断手机上是否插入SD卡,并且应用程序具有读写SD卡的功能

// 当手机上插入SD卡,并且应用程序具有读写SD卡的功能
Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);

第3步:调用getExternalStorageDirectory()来获得SD卡的根目录

File SDCardRoot = Environment.getExternalStorageDirectory();

第4步:读写SD卡中的文件

使用FileInputStream、FileOutputStream、FileReader或FileWrite,来读写SD卡中的文件。这一步与在手机内存中操作文件的方法一样。

向SD卡读写内容的示例如下:

1 . 写入并保存文件内容到SD卡:

// 写入并保存文件内容到SD卡
public void writeFilesToSDCard (String content, String fileName) {

    // 判断SD卡是否存在,并且本程序是否拥有SD卡的权限
    if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {

        // 获得SD卡的根目录
        File sdCardPath = Environment.getExternalStorageDirectory();
        /*
        * 文件输出操作
        * */
        File testFile = new File(sdCardPath, fileName);
        // 初始化文件输出流
        FileOutputStream fileOutputStream = null;
        // 以追加模式打开文件输出流
        try {
            fileOutputStream = new FileOutputStream(testFile, true);
            fileOutputStream.write(content.getBytes());
            // 关闭文件输出流
            fileOutputStream.close();

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

2 . 从SD卡上读取文件内容:

// 从SD卡上读取文件内容
public String readFilesFromSDCard (String fileName) {

    // 定义文件内容字符串
    String content = null;
    // 文件输入流
    FileInputStream fileInputStream = null;

    // 判断SD卡是否存在,并且本程序是否拥有SD卡的权限
    if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {

        // 获得SD卡的根目录
        File sdCardPath = Environment.getExternalStorageDirectory();
        /*
        * 文件输出操作
        * */
        try {
            File testFile = new File(sdCardPath, fileName);
            // 打开文件输入流
            fileInputStream = new FileInputStream(testFile);
            // 将文件输入流存放在ByteArrayOutputStream
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            // 定义每次读取一个字节
            byte[] buffer = new byte[1024];
            // 定义每次读取的字节长度
            int len = 0;
            // 读取文件输入流的内容,并存入ByteArrayOutputStream中
            while ((len = fileInputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, len);
            }
            // 将文件输入流数据以字符串的形式存放
            content = outputStream.toString();
            // 关闭文件输入流
            fileInputStream.close();
            // 关闭ByteArrayOutputStream
            outputStream.close();


        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    // 返回文件内容
    return content;
}

3 . 页面展示逻辑:

private EditText dataInput;
private Button dataShowBtn;
private TextView dataShowText;
private String fileName = "test.txt";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    dataInput = (EditText) findViewById(R.id.data_input);
    dataShowBtn = (Button) findViewById(R.id.data_show_btn);
    dataShowText = (TextView) findViewById(R.id.data_show_text);

    // 按钮点击,则将EditText中的内容写入文件中,并展示出来
    dataShowBtn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // 定义存放写入的文件名
            // 将EditorText中的输入内容以追加模式写入SD卡的文件中
            writeFilesToSDCard(dataInput.getText().toString(), fileName);
            // 输出文件内容,并展示
            dataShowText.setText(readFilesFromSDCard(fileName));
        }
    });
}

4 . activity_main.xml布局文件如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:showIn="@layout/activity_main"
    android:orientation="vertical">
    <EditText
        android:id="@+id/data_input"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:lines="4"
        android:text=""/>
    <Button
        android:id="@+id/data_show_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Write In And Read"/>
    <TextView
        android:id="@+id/data_show_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>

5 . 可在DDMS中查看到新建的text文件。

在真机模拟的话,test.txt文件的保存路径为:"/mnt/sdcard/test.txt"。

但是在Genymotion模拟器中,找了N久也没发现 "/mnt/sdcard/"目录下有新文件或新目录生成,而且该目录无法展开。最后,发现文件保存路径竟然是"mnt/shell/emulated/0/test.txt"。

六. Environment类获取外部存储目录信息

Android应用开发中,常使用Environment类去获取外部存储目录。

在访问外部存储之前一定要先判断外部存储是否已经是可使用(已挂载&可使用)状态,并且需要在AndroidManifest.xml文件中添加外部存储读和写的权限。

Environment类中提供了几个静态常量用于标识外部存储的状态,这些状态都是String类型。

1 . 外部存储的状态标识

状态标识 描述
String MEDIA_BAD_REMOVAL 在没有挂载前存储媒体已经被移除。
String MEDIA_CHECKING 正在检查存储媒体。
String MEDIA_MOUNTED 存储媒体已经挂载,并且挂载点可读写。
String MEDIA_MOUNTED_READ_ONLY 存储媒体已经挂载,挂载点只读。
String MEDIA_NOFS 存储媒体是空白或是不支持的文件系统。
String MEDIA_REMOVED 存储媒体被移除。
String MEDIA_SHARED 存储媒体正在通过USB共享。
String MEDIA_UNMOUNTABLE 存储媒体无法挂载。
String MEDIA_UNMOUNTED 存储媒体没有挂载。

2 . 其他的系统标准目录

属性 描述
public static String DIRECTORY_ALARMS 系统提醒铃声存放的标准目录。
public static String DIRECTORY_DCIM 相机拍摄照片和视频的标准目录。
static String DIRECTORY_DOWNLOADS 下载的标准目录。
static String DIRECTORY_MOVIES 电影存放的标准目录。
static String DIRECTORY_MUSIC 音乐存放的标准目录。
static String DIRECTORY_NOTIFICATIONS 系统通知铃声存放的标准目录。
static String DIRECTORY_PICTURES 图片存放的标准目录。
static String DIRECTORY_PODCASTS 系统广播存放的标准目录。
static String DIRECTORY_RINGTONES 系统铃声存放的标准目录。

3 . Environment类的方法

方法 描述
File getDataDirectory() 获得android data的目录。
File getDownloadCacheDirectory() 获得下载缓存目录。
File getExternalStorageDirectory() 或者外部存储媒体目录。
File getExternalStoragePublicDirectory(String type) 获得特定类型文件的上一级外部存储目录。
String getExternalStorageState() 获得当前外部储存媒体的状态。
File getRootDirectory() 获得android的跟目录。
static boolean isExternalStorageEmulated() 判断设备的外部存储媒体是否是内存模拟的,是则返回true。
static boolean isExternalStorageEmulated(File path) 判断指定文件目录的外部存储媒体是否是内存模拟的,是则返回true。
static boolean isExternalStorageRemovable() 判断设备的外存是否可拆卸,如SD卡,是则返回true。
static boolean isExternalStorageRemovable(File path) 判断指定目录下的外存是否可拆卸,如SD卡,是则返回true。
本文作者:子匠_Zijor,转载请注明出处:http://www.dengzhr.com/others/mobile/742