android用IO实现日记的读写,黑马学习日记_IO篇(首先部分)

----------------------android开发、java培训、期待与您交流! ----------------------

IO:主要用来处理设备之间的数据传输(如硬盘上的文件,内存中的数据),java对数据的操作是通过流的方式,

java操作流的对象存在IO包中,流按数据分为两种,字节流和字符流。

字符流的数据字节流其实都能处理,因为无论什么在计算机上最后都是以字节存在的,但是其中有一部

分数据它是以文本形式存在的,所以为了方便有了字符流,字符流里融合了编码表,而只有文字用到了

编码表,所以字符流用来处理文本形式的数据。

按方向分的话有输入流和输出流之分。

字符流:        字节流:

Writer  Reader   InputStream  OutputStream

这四个基类的子类名称都是以父类的名称为后缀,如FileReader,FileInputStream,

在写有关IO流程序的时候,首先要注意:

1.要注意一定要记得导包,import java.Io.*;

2.记得要进行异常处理,和IO流有关的都会抛异常,原因:例如FileWrite("C:\\abc.txt");

因为括号里的文件名会有可能出错,比如写成(K:\\abc.txt)

3.最后一定要进行关闭流的操作。因为它底层调用的其实是window资源,所以要关闭。

---------------------------------------------------------------------------------------------

下面是IO异常处理方式:

例如;

FileWriter fw = null;//2.所以一般在外面定义引用在try内初始化,这样fw就作用于整个程序中,

try

{

//1.因为会抛异常所以要进行try处理,但是如过把下面这句放在try代码块里面定义fw,那么

//在别的代码块里会访问不到(比如finaly里关流的时候)

//FileWriter fw = new FileWriter(c:\\abc.txt);

fw = new FileWriter(c:\\abc.txt); // 代码1

fw.Write("abcdef"); //代码2

}

catch(IOException e),

{

//异常处理

}

finaly

{

try

{//一定要对关闭的流对象进行判断是否为空

if(fw != null)//写这句的原因:因为如果“代码1”处出现异常被处理了,那么代码里面fw里面也就

//没有被写进东西,所以fw为空。

fw.close();//如果为空的话则不能调用这句,所以要进行下是否为空判断

}

catch(IOException e),

{

//异常处理

}

}

字符流:writer(写)

根据以往经验,要想了解一个体系,是不是都要先从最顶端的开始了解啊?字符流写的方法最顶端的

父类就是writer,它里面有append(),close(), write() 等方法,可以知道它的子类中肯定也都具有

这些功能。既然是字符流,那么它操作的最基本数据就是字符, FileWriter 里的主力方法就是write

方法,就是往文件里写数据的方法,既然是操作字符了,那肯定忘里写单个字符啊字符数组啊,字符串

啊都行。

字符流---创建文件  异常处理如上:

FileWriter fw = new FileWriter("Demo.txt");//  在此目录下创建一文件,如果已经存在会被覆盖掉。

FileWriter fw = new FileWriter("Demo.txt",true);//不覆盖原文件,在末尾处添加

fw.write("abcdefg");//调用write()方法,其实是存在了流(内存)中

fw.flush();//将流对象中缓冲区里的刷新数据至目的地中

fw.close();// close()特点:刷新一次数据然后关闭流

其实,我们不用java也能创建一个文件往里写数据,也就是说windows系统本身就具有这个动作,java能往

windows的文件系统中写入数据,是不是代表着java在调用windos中那个写的动作?这个就是我们所说的流

资源。其实java本身是不能往硬盘里写数据的,我们知道windows和linux系统它们写数据的方式是不是不一

样啊?所以java得靠系统本身的方式来完成对数据的书写。总的来说就是java写数据什么的是不是在调用

windows的系统资源用完了要怎么办?是不是要释放出来,所以close动作是一定要做的。

文件的续写:

建个文件往里面写数据,但是那个文件里已经有数据了该怎么往里续写数据呢?写一次刷新一次,通过

查看API我们发现FileWriter类有一种构造函数

FileWriter(String fileName, boolean append)

参数: fileName - 一个字符串,表示与系统有关的文件名。

append - 一个 boolean 值,如果为 true,则将数据写入文件末尾处,而不是写入文件开始处。

---------------------------------------------------------------------------------------------

字符流 Reader(读)

说完写该说读了,查看API发现Reader类里也有很多和Writer方法,如close()等,但是它里面没有flush();

另外它里面有一群读的方法(read),如读单个字符,或把数据读入到一个数组,另外读文件的话是不是先把

文件传给他啊,所以在创建对象的时候要把指定文件与它相关联。如果不存在会发生文件未找到异常。

字符流---读取文件1 下面是没有进行异常处理的

FileReader fr = new FileReader("Demo.txt");//文件不存在会抛异常

int x = fr.read();//一次读一个会自动往下读,如果在调用一次read方法和打印方法,打印的则是下一个

System.out.println(char(x));//因为返回的是int型,所以要进行类型转换。

//一个文件里面显然不会只有一个字符,像上面所说读一个重写一次方法,会很麻烦,所以会想到循环,如下:

int x = 0;

while((x=fr.read()) != -1)//文件读取到末尾如果没有的话会返回-1

{

System.out.println((char)x);

}

字符流---读取文件2 通过字符数组进行读取,下面是没有进行异常处理的

FileReader fr = new FileReader("Demo.txt");//创建一个文件读取流对象和指定文件相关联

//定义一个字符数组

char[] ch = new char[1024]//一般数组大小会定为1024的整数倍

int num = fr.read(ch);//将读取到的文字存放在数组中,则返回的是字符里面的个数

System.out.println(new String(ch));//将数组变成字符串打印

fr.close();//这一步没有刷新数据,读取文件不用刷新

文件读取2的完整代码:

FileReder fr = null

try

{

fr = new FileReade();

char[] ch = new char[1024];

int num = 0;

while((num = fr.read(ch))!=-1)

{

//打印数组中的有效位,如果数组中只有三个字符,就没必要把1024个全打印出来

System.out.println(new String(buf,0,len));

}

}

catch (IOException e)

{

//异常处理

}

finally

{

try

{

if (fr !=null)

{

fw.close();

}

}

catch (IOException e)

{

//异常处理

}

}

注意:

定义文件路径时,可以用“/”或者“\\”。?

在创建一个文件时,如果目录下有同名文 件将被覆盖。 ?

在读取文件时,必须保证该文件已存在, 否则出异常。

练习:复制文件

部分代码:

FileWriter fw = new FileWriter("copy.txt");//向目的文件中写入数据

FileReader fr = new FileReader("Demo.java");//读取文件中的数据写入流中

char[] buf = new char[1024];

int len = 0;

while((len=fr.read(buf))!=-1)

{

fw.write(buf,0,len);

}

---------------------------------------------------------------------------------------------

字符流的缓冲区: BufferedWriter  BufferedReader

字符流中的读写,如上面方法的话,都是一个一个的读或写,为了提高效率出现了缓冲区,就像

用杯子接水滴,等接满了一杯再喝会比接一滴喝一滴舒服。

像迅雷,BT这些软件它们在下载过程中都有自己的缓冲区,比如它们在服务器下载东西,每次下

载一次性两兆再写到硬盘上从,比每次从服务器下载一点就往硬盘上写一点快吧。这边一顿狂读,

这后到这边再一顿狂写,省的磁头来回的切换,这样效率就提升了很多。

缓冲区的出现是为了提高流的操作效率而出现的。所以在创建缓冲区之前,必须要先有流对象。

该缓冲区中提供了一个跨平台的换行符。newLine();

我们创建一个流对象之后,然后把它当参数传给缓冲区的构造函数,因为缓冲区已经和流相关联了,

所以然后直接用缓冲区的方法就可以了。

字符写入流缓冲区: BufferedWriter

既然缓冲区是为了提高流的效率,那么它存在的前提是要有流。

例如:

FileWriter fw = new FileWriter("Demo.txt");

//只需将需要被提高效率的流当参数传入给缓冲区的构造函数即可

BufferedWriter bfw = new BufferedWriter(fw);

//然后下面就可以用缓冲区的方法了(BufferedWriter也是Write的子类,所以也能用它的方法)

bfw.write("abcde");

bfw.flush();//只要用到缓冲区就要刷新

bfw.close();//关闭缓冲区其是就是关闭了流对象,所以fw.close()就不用再写了

缓冲区有一个新的方法:newLine()这个方法是跨平台的,在window上"\r\n"是换行而在linux上"\n"是换行

只有用到缓冲区对象的时候才能用newLine()方法

例如:

for(intx =0;x<5;x++)

{

bfw.write("abcde");

bfw.newLine();

//为什么要写一次刷新一次? 因为在写的过程中可能会出现一些状况如停电,如果在写好多的情况下

// 停电了没刷新那么文件里面一点也不会有

bfw.flush();

}

---------------------------------------------------------------------------------------------

字符读取流缓冲区: BufferedReader

该缓冲区提供了一次读一行的方法:readLine()因为一行有很多字符。所以它返回的是字符串,读到流的

末尾返回的是null,readLine方法返回的时候只返回回车符之前的数据内容。并不返回回车符。

readLine()方法最终都是从硬盘上一个一个的读取所以最终使用的还是read方法一个一个的读的。

//创建一个读取流对象和文件相关联。

FileReader fr = new FileReader("Demo.txt");

//为了提高效率。加入缓冲技术。将字符读取流对象作为参数传递给缓冲对象的构造函数。

BufferedReader bfr = new BufferedReader(fr);

//下面使用BufferedReader的方法

String s = null;

while((s=bfr.readLine()) !=null)

{

System.out.print(s);

}

bfr.close();

缓冲区特点:

缓冲区的出现提高了对数据的读写效率。?

缓冲区要结合流才可以使用。?

在流的基础上对流的功能进行了增强。

---------------------------------------------------------------------------------------------

装饰设计模式:

一个类的功能如果需要加强,可以在定义一个类来写加强的功能,然后将需要被加强的类

当参数传入加强类,通过构造方法来接收被加强的类。如BufferedReader(FlieRader fr).

模式例如:

class OldMethod //1.

{

public void fuction

{

//原有的功能

}

}

class SuperMethod //2.

{

private OldMethod om;

SuperMethod(OldMethod om)

{

this.om = om;

}

public void superFuction

{

//基于原有而加强的功能

//如果有用到原来的东西,直接调用:om.fuction()

}

}

---------------------------------------------------------------------------------------------

疑问:为什么类2不继承类1呢?

例如下面类OldMethod有三个子类,比如在开发的过程中我们发现这三个子类里面的功能效率有点低我

们想要重写个类来加强一下它们的功能,这时会想到用缓冲技术,那么如果要用继承的话,就会像下

面这样,在后期OldMethod可能还会再增加好多子类,那么在这样写的话整个体系就会显得非常臃肿,所

以要进行优化。

OldMethod

|--OneMethod

|--OneBufferMethod

|--TwoMethod

|--TwoBufferMethod

|--ThreeMethod

|--ThreeBufferMethod

怎么优化呢?既然它们都需要缓冲,所用的技术也都一样,那么就没必要一个一个的写缓冲类来继承了,可以

专门定义一个缓冲类,OldMethod的哪个子类需要缓冲就把哪个当参数传进来。如下:

class MyBufferMethod

{

MyBufferMethod(OneMethod one)

{

}

MyBufferMethod(TwoMethod two)

{

}

MyBufferMethod(ThreeMethod three)

{

}

......//但是这样扩展型还是不太好

}

这时可以发现,无论是哪个类需要缓冲,他们都是OldMethod的子类,这样就想到了多态,我们可以这样定义

一个类来继承.

class MyBufferMethod extends OldMethod//既然MyBufferMethod里的功能和只是那三个子类功能的加强,

{     //所以它也应该属于OldMethod参看下面的(看这里)

MyBufferMethod(OldMethod old)//多态,技能传OneMethod也能传TwoMethod...

{

}

}

最后这个体系就变成了这样:

OldMethod

|--OneMethod

|--TwoMethod

|--ThreeMethod

|--MyBufferMethod

---------------------------------------------------------------------------------------------

我们可以看出装饰模式比继承更灵活,降低了类与类之间的关系

装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了加强功能。所以装饰类

和被装饰类属于同一个体系就像BufferedReader与FileReader同是Reader的子类

---------------------------------------------------------------------------------------------

LineNumberReader: 也是一个装饰类,BufferedReader的子类,所以它也有readLine()方法,

另外还有setLineNumber()和getLineNumber(),意为设置和获取行号。

使用方法如下(没有进行异常处理):

FileReader fr = new FileReader("Demo.txt");

LineNumberReader lnr = new LineNumberReader(fr);

String s = null;

lnr.setLineNumber(10);//可以设置行号的起始值

while((x=lnr.readLine()) != null)

{

System.out.println(lnr.getLineNumber()+"::"+x);

}

---------------------------------------------------------------------------------------------

字节流:基本操作与字符流差不多,别说它里面的write,read方法和字符流里的基本一样,它也能一个一个

的往文件里写数据,也能把数组中的数据一下写到文件中,既能一个一个的读,也能把数据读入到一个数组

中,唯一的区别是字符流写进的是char[],而字节流是往byte[]数组中读或写。另外字节流不仅操作字符,

还可以操作其他媒体文件

基类 InputStream读 OutputStream写

字节流--文件写入,与字符流一样也要处理异常。

FileOutputStream fos = new FileOutputStream("Test.txt");//创建一个字节写入流,与文件相关联

//里面要么写单个字节,要么写字节数组,写字符串的话要把它转成字节类型的

fos.write("abcde".getBytes());//不需要刷新,因为是直接对字节最小单位操作,中间不需要任何转换

fos.close();//关闭流

字节流--文件读取1,一个一个的打印

FileInputStream fis = new FileInputStream("Test.txt");

int ch = 0;//调用read()方法返回的是整数,流末尾返回的是-1;

while((ch=fos.read())!=-1)

{

System.out.println(char(ch));//因为返回的是整数,所以要把它转成字符型打印

}

fos.close();

字节流--文件读取2,将数据读进一个字节数组

FileInputStream fis = new FileInputStream("Test.txt");

byte[] buf = new Byte[1024];

int len = 0;

while((flen=os.read(buf))!=-1)

{

//把数组转换为字符串,按范围打印出来

System.out.println(new String(buf,0,len));

}

字节流--文件读取3,这一种是字节流特有的

FileInputStream fis = new FileInputStream("Test.txt");

//int num = fis.available();调用这个方法可以算出文件中的字符数

byte[] buf = new Byte[fis.available()];//所已就可以定义一个刚刚好的数组了,也就不用循环了

fos.read(buf);//读取文件中的字节存在数组buf中

System.out.println(buf);//不用循环,直接把数组里面的全打印出来

fis.close();

---------------------------------------------------------------------------------------------

注意:

字节流的读一个字节的read方法为什么返回值类型不是byte,而是int。

因为有可能会读到连续8个二进制1的情况,8个二进制1对应的十进制是-1.

那么就会数据还没有读完,就结束的情况。因为我们判断读取结束是通过结尾标记-1来确定的。

所以,为了避免这种情况将读到的字节进行int类型的提升。

并在保留原字节数据的情况前面了补了24个0,变成了int类型的数值。

而在写入数据时,只写该int类型数据的最低8位。

---------------------------------------------------------------------------------------------

字节流缓冲区

//例:通过字节流的缓冲区来完成 Mp3的复制:

BufferedInputStream bufis = new BufferedInputStream(new FileInputStream("c:\\0.mp3"));

BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("c:\\1.mp3"));

int by=0;

while((by=bufis.read())!=-1)

{

fos.write(by);//把从文件中读取的数据写进目的文件

}

fos.close();//有多少流就关多少流

fis.close();

自定义字节流缓冲区:

字节流缓存区的原理是,把一些数据先存进一个数组中,然后在一下取出来。自定义缓冲区的话,思路

就是:要先定义一个数组,然后再把数组中的数据一个一个往外取。用到了数组,怎么往里存呢?我们

知道read(arr)返回的是数组里元素的个数,

那取的时候read方法

是一个一个的往下读的,所以就用到了指针,那什么时候停呢?就是取到数组末尾的时候,就是count=0的时候,

那怎么往数组里面存呢?

class MyBufferInputStream extends

{

private InputStream ips;//定义一个InputStream引用

private byte[] buf = new byte[1024*4];

private int pos = 0,count = 0;//定义一个指针和数据个数的变量

MyBufferInputStream(InputStream ips)//把需要缓存的文件当参数传给缓冲器的构造函数

{

this ips = ips;

}

//要对外提供一个read方法,就像BufferInputStream,一次读一个字节(从缓冲区即字符数组中读取)

public int myRead()throws IOException//进行异常处理

{

//通过in对象读取硬盘上数据,并存储buf中。

if(count==0)//5.所以当数组中元素为0的时候,是先存再取

{

count = ips.read(buf);//1.把数据读取到数组中,返回的是数组里元素的个数

if(count<0)//

return -1;

pos = 0;//

byte b = buf[pos];//2.往数组里存满了是不是就该把数组里的数据取出来放缓冲区里啦

count--;//3.把数组里的数据往缓冲区里装的时候是不是装一个,数组里就少一个啊?

pos++;//4.一个一个的把数组里的取出来,是不是就是指针越来越往后移啊

return b&255;

}

else if(count>0)//6.而当数组里有数据的时候直接取

{

byte b = buf[pos];

count--;

pos++;

return b&0xff;

}

return -1;

}

}

读取键盘录入:

System.out:对应的是标准输出设备,控制台。

System.in:对应的标准输入设备:键盘。in 是标准输入流对应的是InputStream,所以能用read()等方法

例如:

InputStream in = System.in;//System调用in方法之后返回的是一个字节读取流

int by = in.read();//读取一个字节字符流字节流读取一个数据返回的都是int型

System.out.println(by);//控制台将会等待输入运行代码

部分代码:

import java.io.*;

class IODemo

{

public static void main(String[] args) throws IOException

{

InputStream ins = System.in;

StringBuilder sb = new StringBuilder();

while(true)

{

int ch = ins.read();

if(ch=='\r')

continue;

if(ch=='\n')

{

String s = sb.toString();

//sb.delete(0,sb.length());

if("over".equals(s))

break;

System.out.println(s.toUpperCase());

sb.delete(0,sb.length());

}

else

sb.append((char)ch);

}

}

}

然后发现以上代码与我们自定义 BufferedReader时写的ReaderLine代码差不多,这时就考虑能不能

直接拿过来用呢?但是 BufferedReader是字符流,而InputStream是字节流,它是字节流要用字符流

的东西,怎么办?是不是要看看有没有能把字节流转为字符流的东西啊?通过查看java API发现,还

真有个转换流,下面请看java io(2)。

----------------------android开发、java培训、期待与您交流! ----------------------

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值