Andorid文件IO解析

前言

作为初学者,很多人都很容易被所谓的“流”搞晕,IO在应用有好几个方式,代码都差不多,今天我来详细区分讲解下

<br />

IO的 分类

我们来借用一位兄弟的图

常用的流区分

节点流
通俗的理解就是:单纯的用来传送数据,并不对数据进行额外处理如下:
父 类 InputStream OutputStream Reader Writer
文 件 FileInputStream FileOutputStrean FileReader FileWriter 文件进行处理的节点流

处理流
通俗的理解就是:在节点流外附加一层处理,增加效率如:
BufferedImputStrean BufferedOutputStream BufferedReader BufferedWrite等
<br />

IO常用的类对应的方法

字节流常用方法

InputStream
(1)从流中读取数据
int read() 读取一个字节,返回值为所读得字节
int read(byte b[]) 读取多个字节,放置到字节数组b中,通常读取的字节数量为b的长度,返回值为实际独取的
字节的数量。
int read(byte b[] ,int off,int len)读取len个字节,放置到以下标off开始字节数组b中,返回值为实际
读取的字节的数量。
int available() 返回值为流中尚未读取的字节的数量。
long skip(long n);读指针跳过n个字节不读,返回值为实际跳过的字节数量
(2)关闭流
close() 流操作完毕后必须关闭
(3)使用输入流中的标记
void mark(int readlimit)纪录当前指针的所在位置.readlimit表示读指针读出的readlimit个字节后
所标记的指针位置才实效。
void reset() 把读指针重新指向用mark方法所记录的位置
boolean markSupported() 当前的流是否支持读指针的记录功能。

OutputStream
(1)输出数据
void write(int b)往流中写一个字节b
void write(byte b[])往流中写一个字节数组b
void write(byte b[],int off,int len)把字节数组b中从下标off开始,长度为len的字节写入流中
(2)
flush()刷空输出流,并输出所有被缓存的字节
由于某些流支持缓存功能,该方法将把缓存中所有内容强制输出到流中。
(3)关闭流
close()流操作完毕后必须关闭。

相对应的FileInputStream /FileOutputStream

FileInputStream 和 FileOutputStream分别是InputStream 和 OutputStream的子类,往往使用FileInputStream 和 FileOutputStream这两个子类去就可以从一个指定文件中读取或者向某一个文件中写入数据。

** public FileInputStream openFileInput (String name)** :打开输入流文件名
** public FileOutputStream openFileOutput (String name, int mode)** :打开输出流文件名

mode参数主要有:

MODE_PRIVATE :指定改数据只能被本程序读写

MODE_APPEND :以追加方式打开,可向该文件夹中追加内容

MODE_WORLD_READABLE:可以被其他程序读,但不能写

MODE_WORLD_WRITEABLE:可被其他读写。


字符流常用方法

Reader常用方法:

int read()从输入流中读取单个字符,返回读取的字符
int read(byte[] c) 从输入流中读取c.length长度的字符,保存到字符数组c中,返回实际读取的字符数
read(char[] c,int off,int len) 从输入流中读取最多len的长度字符,保存到字符数组c中,保存的位置从off位置开始,返回实际读取的字符长度
void close() 关闭流

Writer常用方法:

write(String str)将str字符串里的字符输出到指定输出流中
write(String str,int off,int len) 将str字符串里从off位置开始长度为len的字符输出到输出流中
void close() 关闭输出流
void flush() 刷新输出流
<br />
相对应的FileReader/FileWriter
FileReader fr = new FileReader(String fileName);//使用带有指定文件的String参数的构造方法。
FileWriter fw = new FileWriter(String fileName);//创建字符输出流类对象和已存在的文件相关联。文件不存在的话,并创建。
FileWriter fw = new FileWriter(String fileName,boolean append);//创建字符输出流类对象和已存在的文件相关联,并设置该该流对文件的操作是否为续写。


需要在AndroidMainfset.xml文件中进行权限的配置:
1.SDCard中创建与删除文件权限:

<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>

2.SDCard写入数据权限

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

<br />

例子

可以根据例子中代码来区分,顺序是:
writeFileOutputStream()方法写入文件,readFileInputStream()读取文件。
FileReader()方法写入文件, FileWriter()读取文件。

    //保存的时候是在文件内容中连续写入,也就是在之前保存的数据基础上再次写入。
    private void writeFileOutputStream() {
        try {
            FileOutputStream fos = openFileOutput("file.txt", Context.MODE_PRIVATE);
            String inputFileContext = write_edt.getText().toString();
            fos.write(inputFileContext.getBytes());
            fos.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //读取文件是把整个文件的内容进行读取。如果要加入解析,则保存的时候保存为特殊格式。
    private void readFileInputStream() {
        try {
            FileInputStream fis = openFileInput("file.txt");
            //注意这个方法,可以换成   byte[] buffer = new byte[1024];
            byte[] buffer = new byte[fis.available()];
            fis.read(buffer);
            read_edt.setText(new String(buffer));
            fis.close();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }


    private void FileReader() {
        String content = "";//读取到的内容
        String temp = "";
        FileReader fr = null;
        int ch = 0;
        File extDir = Environment.getExternalStorageDirectory();
        String filename = "downloaded.txt";
        File fullFilename = new File(extDir, filename);
        try {
            fr = new FileReader(fullFilename);

            //只能读取一段分行就读取不到了
//            while ((ch = fr.read()) != -1) {
//                temp += (char) ch;
//            }
            BufferedReader br = new BufferedReader(fr);
            //一行一行读取
            while ((content = br.readLine()) != null) {
                temp += content + "\r\n";
            }
            read_edt.setText(temp);
            fr.close();
            br.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void FileWriter() {
        //2,以字符的形式直接写入文件
        File extDir = Environment.getExternalStorageDirectory();
        String filename = "downloaded.txt";
        File fullFilename = new File(extDir, filename);
        try {
            FileWriter fw = new FileWriter(fullFilename, false);//第二个参数:是否以追加的模式将字符写入
//            fw.write(write_edt.getText().toString());//直接将字符写入文件
            BufferedWriter bw = new BufferedWriter(fw);//又包裹一层缓冲流 增强IO功能
            bw.write(write_edt.getText().toString());
            bw.flush();//将内容一次性写入文件  ,否则会出现短缺字符
            bw.close();
            fw.close();//BufferedWriter,再关闭FileWriter
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

遇到需要注意的问题

第一个问题:

 //注意这个方法,可以换成   byte[] buffer = new byte[1024];
 byte[] buffer = new byte[fis.available()];

要一次读取多个字节时,经常用到InputStream.available()方法,这个方法可以在读写操作前先得知数据流里有多少个字节可以读取。需要注意的是,如果这个方法用在从本地文件读取数据时,一般不会遇到问题,但如果是用于网络操作,就经常会遇到一些麻烦。比如,Socket通讯时,对方明明发来了1000个字节,但是自己的程序调用available()方法却只得到900,或者100,甚至是0,感觉有点莫名其妙,怎么也找不到原因。其实,这是因为网络通讯往往是间断性的,一串字节往往分几批进行发送。本地程序调用available()方法有时得到0,这可能是对方还没有响应,也可能是对方已经响应了,但是数据还没有送达本地。对方发送了1000个字节给你,也许分成3批到达,这你就要调用3次available()方法才能将数据总数全部得到。

如果这样写代码:

  int count = in.available(); 
  byte[] b = new byte[count]; 
  in.read(b); 

在进行网络操作时往往出错,因为你调用available()方法时,对发发送的数据可能还没有到达,你得到的count是0。
需要改成这样:

  int count = 0; 
  while (count == 0) { 
   count = in.available(); 
  } 
  byte[] b = new byte[count]; 
  in.read(b);

第二个问题:
我们可以看一下以下代码,随便选一组:openFileOutput构造方法和FileReader构造方法

   FileOutputStream fos = openFileOutput("file.txt", Context.MODE_PRIVATE);
   File extDir = Environment.getExternalStorageDirectory();
   String filename = "downloaded.txt";
   File Filename = new File(extDir, filename);
   fr = new FileReader(Filename);

构造方法里面的参数FileOutputStream()可以随意定一个"file.txt"放进去即可,不用指定路径(应该是系统默认了,读写/data/data/<应用程序名>目录下的文件),而FileReader()却是放入的要么是有指定路径的File,要么是路径名,若是随意放一个"file.txt"会报无法找到路径的错误。

第三个问题:

  FileWriter fw = new FileWriter(fullFilename, false);//第二个参数:是否以追加的模式将字符写入
//            fw.write(write_edt.getText().toString());//直接将字符写入文件
            BufferedWriter bw = new BufferedWriter(fw);//又包裹一层缓冲流 增强IO功能
            bw.write(write_edt.getText().toString());
            bw.flush();//将内容一次性写入文件  ,否则会出现短缺字符
            bw.close();
            fw.close();//BufferedWriter,再关闭FileWriter

一定要先关闭BufferedWriter缓存再关闭FileWriter,否则会报错。顺带提一下BufferedWriter这里就是处理流,简单的加入这段代码既可以增加效率。
<br />
相应的文件目录写

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,277评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,777评论 1 298
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,946评论 0 245
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,271评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,636评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,767评论 1 221
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,989评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,733评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,457评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,674评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,155评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,518评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,160评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,114评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,898评论 0 198
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,822评论 2 280
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,705评论 2 273

推荐阅读更多精彩内容