android 对象转字节,Android之IO流详解

(1)概念

文件在程序中是以流的形式来操作的。

流:是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两个存储位置之间的传输称为流。流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。

另外,在下文中演示IO的时候,会用到文件路径的获取。我特地整理了一篇博客Android之获取内、外置存储器路径

(2)分类

按流向分类:输入流和输出流

输入流:用于读文件,并将读到的数据暂存到内存。

输出流:用于写文件,将内存中的数据存入到文件。

按传输单位分类:字节流和字符流

字节流:可以用于读写二进制文件及任何类型文件。

字符流:可以用于读写文本文件。

(3)字节流和字符流的区别?

读写单位不同

字节流以字节(1 byte,1byte=8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。

处理对象不同

字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。

缓存

字节流在操作的时候本身是不会用到缓冲区的,是文件本身的直接操作的;而字符流在操作的时候下后是会用到缓冲区的,是通过缓冲区来操作文件。

总结:优先选用字节流。因为硬盘上的所有文件都是以字节的形式进行传输或者保存的,包括图片等内容。字符只是在内存中才会形成的,所以在开发中,字节流使用广泛。

(4)超类

字节流: InputStream(读入流) OutputStream(写出流)

字符流: Reader(读入流) Writer (写出流)

它们都是抽象类。

(5)文件流

为了操作文件,所以出现了文件流,用文件流来对文件进行读写操作。

字节流:

-----文件输入流:FileInputStream: 使用read方法读取文件

-----文件输出流:FileOutputStream : 使用write方法将二进制写到文件

字符流:

-----文件输入流:FileReader: 使用read方法读取文件

-----文件输出流:FileWriter: 使用write方法将内容写到文件

例子一: 使用FileOutputStream将字符串写入文件,在使用 FileInputStream将文件的内容读出来。

//是否存在外置存储器

boolean isExternalStorageExist = Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());

boolean isRootDirExist = Environment.getExternalStorageDirectory().exists();

String filePath = "";

if (isExternalStorageExist && isRootDirExist) {

filePath = FileDirUtil.getInstance().getExternalStorageDirectory() + File.separator + "filetext.txt";

} else {

filePath = FileDirUtil.getInstance().getFilesDir() + File.separator + "filetext.txt";

}

File file = new File(filePath);

if(!file.exists()){

//如果文件不存在,则创建一个文件

try {

file.createNewFile();

} catch (IOException e) {

e.printStackTrace();

}

}

FileOutputStream fos = null;

FileInputStream fis = null;

String text = "abcdefg";

try {

fos = new FileOutputStream(filePath);

fos.write(text.getBytes());//必须将字符串转成字节数组才能写入输出流

fos.flush();//写完之后刷新一下才能真正将字符串写入文件

fis = new FileInputStream(filePath);

byte[] cache = new byte[text.getBytes().length];

StringBuilder sb = new StringBuilder();

fis.read(cache);//由于字符串确定长度,那么cache的长度也确定了,所以这里只要读一次就能全部读完

sb.append(new String(cache));

Log.d("aaa", sb.toString());

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}finally {

if(fos != null){

try {

fos.close();

} catch (IOException e) {

e.printStackTrace();

}

}

if(fis != null){

try {

fis.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

例子二: 使用FileInputStream和FileOutputStream实现文件的拷贝。

//是否存在外置存储器

boolean isExternalStorageExist = Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());

boolean isRootDirExist = Environment.getExternalStorageDirectory().exists();

String filePath = "";

if (isExternalStorageExist && isRootDirExist) {

filePath = FileDirUtil.getInstance().getExternalStorageDirectory() + File.separator + "filetext.txt";

} else {

filePath = FileDirUtil.getInstance().getFilesDir() + File.separator + "filetext.txt";

}

File file = new File(filePath);

if(!file.exists()){

//如果文件不存在,则创建一个文件

try {

file.createNewFile();

} catch (IOException e) {

e.printStackTrace();

}

}

String copy_filePath = "";

if (isExternalStorageExist && isRootDirExist) {

copy_filePath = FileDirUtil.getInstance().getExternalStorageDirectory() + File.separator + "filetext_copy.txt";

} else {

copy_filePath = FileDirUtil.getInstance().getFilesDir() + File.separator + "filetext_copy.txt";

}

FileOutputStream fos = null;

FileInputStream fis = null;

try {

fis = new FileInputStream(filePath);

fos = new FileOutputStream(copy_filePath);

byte[] cache = new byte[1024];//由于读取的文件长度不确定,所以就暂定一个大小为1024字节的临时缓存

int index = 0;

while ((index = fis.read(cache)) != -1){//如果读完就会返回-1

fos.write(cache, 0, index);//将缓存cache的[0, index]范围的内容写入文件

fos.flush();//写完之后刷新一下才能真正将字符串写入文件

}

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}finally {

if(fis != null){

try {

fis.close();

} catch (IOException e) {

e.printStackTrace();

}

}

if(fos != null){

try {

fos.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

例子三: 使用FileReader和FileWriter实现文件的拷贝,和上面字节流写法类似。

//是否存在外置存储器

boolean isExternalStorageExist = Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());

boolean isRootDirExist = Environment.getExternalStorageDirectory().exists();

String filePath = "";

if (isExternalStorageExist && isRootDirExist) {

filePath = FileDirUtil.getInstance().getExternalStorageDirectory() + File.separator + "filetext.txt";

} else {

filePath = FileDirUtil.getInstance().getFilesDir() + File.separator + "filetext.txt";

}

File file = new File(filePath);

if(!file.exists()){

//如果文件不存在,则创建一个文件

try {

file.createNewFile();

} catch (IOException e) {

e.printStackTrace();

}

}

String copy_filePath = "";

if (isExternalStorageExist && isRootDirExist) {

copy_filePath = FileDirUtil.getInstance().getExternalStorageDirectory() + File.separator + "filetext_copy.txt";

} else {

copy_filePath = FileDirUtil.getInstance().getFilesDir() + File.separator + "filetext_copy.txt";

}

FileWriter fw = null;

FileReader fr = null;

try {

fr = new FileReader(filePath);

fw = new FileWriter(copy_filePath);

char[] cache = new char[1024];//由于读取的文件长度不确定,所以就暂定一个大小为1024字符数的临时缓存

int index = 0;

while ((index = fr.read(cache)) != -1){//如果读完就会返回-1

fw.write(cache, 0, index);//将缓存cache的[0, index]范围的内容写入文件

fw.flush();//写完之后刷新一下才能真正将字符串写入文件

}

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}finally {

if(fr != null){

try {

fr.close();

} catch (IOException e) {

e.printStackTrace();

}

}

if(fw != null){

try {

fw.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

(6)缓冲流

缓冲流是对文件流的操作的功能的加强,提高了数据的读写效率。既然缓冲流是对流的功能和读写效率的加强和提高,所以在创建缓冲流的对象时应该要传入要加强的流对象。

BufferedXxx是对其他流的封装,符合装饰设计模式。

字节缓冲流:

-----缓冲输入流:BufferedInputStream: 使用read读取文件

-----缓冲输出流:BufferedOutputStream : 使用write将二进制写入文件

字符缓冲流:

-----缓冲输入流:BufferedReader: 使用read或者readLine读取文件,使用readLine可能会出现中文乱码的问题。

-----缓冲输出流:BufferedWriter: 使用write将内容写入文件

例子一: 使用BufferedInputStream和BufferedInputStream实现文件的拷贝,和FileInputStream+FileOutputStream实现文件拷贝的代码基本一致。使用装饰设计模式,在FileInputStream的基础上再次封装,变成了BufferedInputStream,在FileOutputStream的基础上再次封装,变成了BufferedInputStream。

//是否存在外置存储器

boolean isExternalStorageExist = Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());

boolean isRootDirExist = Environment.getExternalStorageDirectory().exists();

String filePath = "";

if (isExternalStorageExist && isRootDirExist) {

filePath = FileDirUtil.getInstance().getExternalStorageDirectory() + File.separator + "filetext.txt";

} else {

filePath = FileDirUtil.getInstance().getFilesDir() + File.separator + "filetext.txt";

}

File file = new File(filePath);

if(!file.exists()){

//如果文件不存在,则创建一个文件

try {

file.createNewFile();

} catch (IOException e) {

e.printStackTrace();

}

}

String filePath_copy = "";

if (isExternalStorageExist && isRootDirExist) {

filePath_copy = FileDirUtil.getInstance().getExternalStorageDirectory() + File.separator + "filetext_copy.txt";

} else {

filePath_copy = FileDirUtil.getInstance().getFilesDir() + File.separator + "filetext_copy.txt";

}

BufferedInputStream bis = null;

BufferedOutputStream bos = null;

try {

bis = new BufferedInputStream(new FileInputStream(filePath));

bos = new BufferedOutputStream(new FileOutputStream(filePath_copy));

byte[] cache = new byte[1024];//由于读取的文件长度不确定,所以就暂定一个大小为1024字节数的临时缓存

int index = 0;

while ((index = bis.read(cache)) != -1){//如果读完就会返回-1

bos.write(cache, 0, index);//将缓存cache的[0, index]范围的内容写入文件

bos.flush();//写完之后刷新一下才能真正将字符串写入文件

}

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}finally {

if(bis != null){

try {

bis.close();

} catch (IOException e) {

e.printStackTrace();

}

}

if(bos != null){

try {

bos.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

例子二: 使用BufferedReader和BufferedWriter实现文件拷贝

BufferedReader新增了一个readLine方法,请谨慎使用,因为容易导致编码问题,比如“中文乱码”。

//是否存在外置存储器

boolean isExternalStorageExist = Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());

boolean isRootDirExist = Environment.getExternalStorageDirectory().exists();

String filePath = "";

if (isExternalStorageExist && isRootDirExist) {

filePath = FileDirUtil.getInstance().getExternalStorageDirectory() + File.separator + "filetext.txt";

} else {

filePath = FileDirUtil.getInstance().getFilesDir() + File.separator + "filetext.txt";

}

File file = new File(filePath);

if(!file.exists()){

//如果文件不存在,则创建一个文件

try {

file.createNewFile();

} catch (IOException e) {

e.printStackTrace();

}

}

String filePath_copy = "";

if (isExternalStorageExist && isRootDirExist) {

filePath_copy = FileDirUtil.getInstance().getExternalStorageDirectory() + File.separator + "filetext_copy.txt";

} else {

filePath_copy = FileDirUtil.getInstance().getFilesDir() + File.separator + "filetext_copy.txt";

}

BufferedReader br = null;

BufferedWriter bw = null;

try {

br = new BufferedReader(new FileReader(filePath));

bw = new BufferedWriter(new FileWriter(filePath_copy));

String temptext;

while ((temptext = br.readLine()) != null){//如果读完就会返回-1

bw.write(temptext);//将缓存cache的[0, index]范围的内容写入文件

bw.flush();//写完之后刷新一下才能真正将字符串写入文件

}

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}finally {

if(br != null){

try {

br.close();

} catch (IOException e) {

e.printStackTrace();

}

}

if(bw != null){

try {

bw.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

以上需要注意的是:

br = new BufferedReader(new FileReader(filePath));

bw = new BufferedWriter(new FileWriter(filePath_copy));

以上两句话的默认编码是GBK或者gb2312,如果我们读取一个“UTF-8”格式的文件时,就会出现乱码。

有关中文乱码的问题,我有必要重点提一下:

IO操作的默认编码是UTF-8

以下两句代码的默认编码就是UTF-8

//默认编码是UTF-8

br = new BufferedReader(new FileReader(filePath));

//默认编码是UTF-8

bw = new BufferedWriter(new FileWriter(filePath_copy));

相当于

//可以指定一个编码

br = new BufferedReader(new InputStreamReader(new FileInputStream(filePath), "UTF-8"));

//可以指定一个编码

bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filePath), "UTF-8"));

当读取文件时,如果文件的编码是GBK,我们读取的时候必须指定一个编码,这个时候我们必须使用转换流来指定编码格式。(有关转换流的只是下面会讲)

br = new BufferedReader(new InputStreamReader(new FileInputStream(filePath), "GBK"));

当我们将数据写到文件时,默认编码依然是UTF-8,如果需要指定编码格式,就使用下面的代码

bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filePath_copy), "GBK"));

假如我们指定“UTF-8”编码将数据写入文件,此时,当前文件的编码就是“UTF-8”,当我们使用三方工具打开文件时,如果出现乱码,那么表明该工具的默认打开的编码不是“UTF-8”。

(7)转换流

顾名思义,转换流就是讲字节流转成字符流,从构造方法就可以看出来了

InputStreamReader(InputStream in, String charsetName)

OutputStreamWriter(OutputStream out, String charsetName)

完整的代码如下:

//是否存在外置存储器

boolean isExternalStorageExist = Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());

boolean isRootDirExist = Environment.getExternalStorageDirectory().exists();

String filePath = "";

if (isExternalStorageExist && isRootDirExist) {

filePath = FileDirUtil.getInstance().getExternalStorageDirectory() + File.separator + "filetext.txt";

} else {

filePath = FileDirUtil.getInstance().getFilesDir() + File.separator + "filetext.txt";

}

File file = new File(filePath);

if(!file.exists()){

//如果文件不存在,则创建一个文件

try {

file.createNewFile();

} catch (IOException e) {

e.printStackTrace();

}

}

String filePath_copy = "";

if (isExternalStorageExist && isRootDirExist) {

filePath_copy = FileDirUtil.getInstance().getExternalStorageDirectory() + File.separator + "filetext_copy.txt";

} else {

filePath_copy = FileDirUtil.getInstance().getFilesDir() + File.separator + "filetext_copy.txt";

}

InputStreamReader isr = null;

OutputStreamWriter osw = null;

try {

isr = new InputStreamReader(new FileInputStream(filePath), "UTF-8");

osw = new OutputStreamWriter(new FileOutputStream(filePath_copy), "GBK");

char[] cache = new char[1024];

int index;

while ((index = isr.read(cache, 0, cache.length)) != -1){//如果读完就会返回-1

osw.write(cache, 0, index);//将缓存cache的[0, index]范围的内容写入文件

osw.flush();//写完之后刷新一下才能真正将字符串写入文件

}

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}finally {

if(isr != null){

try {

isr.close();

} catch (IOException e) {

e.printStackTrace();

}

}

if(osw != null){

try {

osw.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

(8)对象流

主要的作用是用于写入对象信息与读取对象信息。 对象信息一旦写到文件上那么对象的信息就可以做到持久化了。

对象的输出流: ObjectOutputStream

对象的输入流: ObjectInputStream

对象的输出流将指定的对象写入到文件的过程,就是将对象序列化的过程,对象的输入流将指定序列化好的文件读出来的过程,就是对象反序列化的过程。既然对象的输出流将对象写入到文件中称之为对象的序列化,那么可想而知对象所对应的class必须要实现Serializable接口。

代码如下:

public class UserInfo implements Serializable{//必须实现Serializable接口

private String name;

private int age;

public UserInfo(String name, int age) {

this.name = name;

this.age = age;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

}

//是否存在外置存储器

boolean isExternalStorageExist = Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());

boolean isRootDirExist = Environment.getExternalStorageDirectory().exists();

String filePath = "";

if (isExternalStorageExist && isRootDirExist) {

filePath = FileDirUtil.getInstance().getExternalStorageDirectory() + File.separator + "filetext.txt";

} else {

filePath = FileDirUtil.getInstance().getFilesDir() + File.separator + "filetext.txt";

}

File file = new File(filePath);

if(!file.exists()){

//如果文件不存在,则创建一个文件

try {

file.createNewFile();

} catch (IOException e) {

e.printStackTrace();

}

}

String filePath_copy = "";

if (isExternalStorageExist && isRootDirExist) {

filePath_copy = FileDirUtil.getInstance().getExternalStorageDirectory() + File.separator + "filetext_copy.txt";

} else {

filePath_copy = FileDirUtil.getInstance().getFilesDir() + File.separator + "filetext_copy.txt";

}

ObjectInputStream ois = null;

ObjectOutputStream oos = null;

try {

oos = new ObjectOutputStream(new FileOutputStream(filePath));

UserInfo userInfo1 = new UserInfo("张三", 14);

UserInfo userInfo2 = new UserInfo("李四", 15);

oos.writeObject(userInfo1);

oos.writeObject(userInfo2);

oos.flush();

ois = new ObjectInputStream(new FileInputStream(filePath));

oos = new ObjectOutputStream(new FileOutputStream(filePath_copy));

Object object;

while ((object = ois.readObject()) != null){//如果获取的对象不为空

if(object instanceof UserInfo){

UserInfo userInfo = (UserInfo) object;

Log.d("aaa", "name:"+userInfo.getName()+"===age:"+userInfo.getAge());

oos.writeObject(userInfo);

}

oos.flush();//写完之后刷新一下才能真正将字符串写入文件

}

} catch (ClassNotFoundException e) {

e.printStackTrace();

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

} finally {

if(ois != null){

try {

ois.close();

} catch (IOException e) {

e.printStackTrace();

}

}

if(oos != null){

try {

oos.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

以上代码体现了对象的序列化和反序列化的过程。主要注意的是,对象必须实现Serializable接口。

(9)ByteArrayInputStream

包含一个内部缓冲区,其中包含可以从流中读取的字节。 内部计数器跟踪由read方法提供的下一个字节。关闭一个ByteArrayInputStream没有任何效果。 该流中的方法可以在流关闭后调用,而不生成IOException 。意思就是说,比如文件流的处理对象的外存中的文件,而它的处理对象是内存中的缓冲区。它是从一个内存读到另一个内存方式。

ByteArrayInputStream bis = null;

ByteArrayOutputStream bos = null;

try {

String text = "我是中国人!123!abc!";

//第一个数组

byte[] textBytes = text.getBytes();

bis = new ByteArrayInputStream(textBytes);

bos = new ByteArrayOutputStream();

//第二个数组

byte[] tempText = new byte[1024];

int index;

while ((index = bis.read(tempText)) != -1){

bos.write(textBytes, 0 , index);

}

} catch (IOException e) {

e.printStackTrace();

} finally {

if(bis != null){

try {

bis.close();

} catch (IOException e) {

e.printStackTrace();

}

}

if(bos != null){

try {

bos.close();

} catch (IOException e) {

e.printStackTrace();

}

}

(10)数据流

DataInputStream和DataOutputStream

(11)打印流

PrintStream和PrintWriter

(12)随机访问文件流

RandomAccessFile

(13)结构图

e591f1cfddf8?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

图片.png

e591f1cfddf8?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

图片.png

e591f1cfddf8?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

图片.png

结构图文件已保存到百度网盘:

说明:

这篇写到最后也懒得多写了,因为我自己都看的比较乱,等后期有时间了我会重新整理下。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值