JavaIO流


属于IO包
Reader 往外读,Writer往里写。
读数据就像读报纸,写数据就像写字。都得有对象,比如读报纸,先得有报纸
而写字也是一样,至少有一个地方让你写。比如写在纸上。


字符流的对象中融合了编码表,一般用于处理文字,文本文件。
而字节流用于处理媒体文件,比如图片,视频。。。
字符流是基本字节流的,媒体文凭和文本文件都可以处理
所以说字节流是通用的。


IO流常见操作就是操作文件。


/*
 演示IO流的FileWriter
 */
package com.io;
import java.io.*;
public class FileWriterDemo
{
public static void main(String[] args) throws IOException
{
// 创建一个文件用于存放写入的数据,如果该文件已经存在就覆盖。
FileWriter fw = new FileWriter("e:/dmeo.txt");
fw.write("dajflkdafj");//向dmo.txt文件中写入数据
fw.flush();//刷新缓冲区中的数据到文件中去。
fw.close();//关闭文件流,但要先刷新一次。
}
}




---------------------------------------------------------------------------------
IO异常处理:


/*
 IO异常处理。
 */
package com.io;
import java.io.*;
public class IOExceptionDemo
{
public static void main(String[] args)
{
FileWriter fw = null;
try
{
fw = new FileWriter("e:/demo.txt");
fw.write("java cee");
fw.flush();
}
catch(IOException e)
{
System.out.println(e.toString());
}
finally
{
try
{
if(fw!=null)//关闭流之前一定要先判断一下对象是不是空指针。
fw.close();
}
catch(IOException e)
{
System.out.println(e.toString());
}
}
}
}


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


数据的续写,在原有的数据基础上再写数据。


windows系统中换行符 \r\n
Linux系统中换行符  \r




/*
 文件的续写
 */
package com.io;
import java.io.*;
public class FileContuneDemo
{
public static void main(String[] args)
{

FileWriter fw = null;
try
{
// 创建一个文件,是用来存放文件的目的地。
// true参数表示不覆盖已经存放的文件,并且把数据续写到文件的末尾
fw = new FileWriter("e:/demo.txt",true);
fw.write("\r\ndjalkfdjaoifejaifueaifuda");//并且换一行
}
catch(IOException e)
{
System.out.println(e.toString());
}
finally
{
try
{
if(fw!=null)
fw.close();
}
catch(IOException e)
{
System.out.println(e.toString());
}
}
}


}


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


文本文件的读取方式一:
读文件就像读报纸一样,先得有报纸,所以构造函数没有空参数的。


每个文件的结尾处都有一个标识用以区分不同的文件。
当read读到文件结尾处时就返回-1




package com.io;
import java.io.*;
public class FileReaderDemo
{


public static void main(String[] args)
{
FileReader fr = null;
try
{
fr = new FileReader("e:/demo.txt");
for(int ch=0;(ch=fr.read())!=-1;)
{
System.out.println("ch="+(char)ch);
}

}
catch(IOException e)
{
System.out.println(e.toString());
}
finally
{
try
{
if(fr!=null)
fr.close();
}
catch(IOException e)
{
System.out.println(e.toString());
}
}
}
}


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


文本文件的读取方式二:


读取字符数组,通过字符数组进行读取。


一个字符等于两个字节。


/*
 字符数组缓冲区读取文本文件
 */
package com.io;
import java.io.*;
public class CharReaderDemo
{
public static void main(String[] args)
{
FileReader fr = null;
try
{
// 创建文件读取流对象
fr = new FileReader("e:/demo.txt");
//加入字符数组缓冲区读取文本
char[] buf = new char[1024];
for(int num=0;(num=fr.read(buf))!=-1;)
{
System.out.println("buf"+new String(buf,0,num));
}
}
catch(IOException e)
{
System.out.println(e.toString());
}
finally
{
try
{
if(fr!=null)
fr.close();
}
catch(IOException e)
{
System.out.println(e.toString());
}
}
}
}




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




读取硬盘上的一个.java文件


/*
 读一个JAVA文件
 */
package com.io;
import java.io.*;
public class ReadJavaDemo
{
public static void main(String[] args)
{
FileReader fr = null;
try
{
fr = new FileReader("D:\\Workspaces\\MyEclipse 10\\TestProject\\src\\com\\io\\ReadJavaDemo.java");
// 加入数组缓冲区技术读取数据
char[] buf = new char[1024];
for(int num=0; (num=fr.read(buf))!=-1;)
System.out.println(new String(buf,0,num));
}
catch(IOException e)
{
System.out.println(e.toString());
}
finally
{
try
{
if(fr!=null)
fr.close();
}
catch(IOException e)
{
System.out.println(e.toString());
}
}
}


}
----------------------------------------------------------------------------------
将C盘的一个文本文件复制到D盘。
复制原理:
就是将C盘下的文件数据存储到D盘文件中


步骤:
1.在D盘创建一个文件,用于存储C盘文件中的数据
2.定义读取流和C盘文件关联
3.通过不断的读写完成数据存储
4.关闭资源






/*
 复制文件
 */
package com.io;
import java.io.*;
public class CopyFile
{
public static void main(String[] args)
{
copyFile_2();
// copyFile_1();
}
// 复制文件方式一
public static void copyFile_1()
{
FileWriter fw = null;
FileReader fr = null;
try
{
// 创建文件复制的目的地
fw = new FileWriter("d:/copyFile.txt");
// 创建需要复制的文件关联
fr = new FileReader("c:/RHDSetup.log");
for(int len=0; (len=fr.read())!=-1;)
{
fw.write(len);
}
}
catch(IOException e)
{
throw new RuntimeException("数据流读取失败");
}
finally
{
if(fw!=null)
try
{
fw.close();
}
catch(IOException e)
{
throw new RuntimeException("关闭写入流失败。");
}
if(fr!=null)
try
{
fr.close();
}
catch(IOException e)
{
throw new RuntimeException("读取流关闭失败");
}

}
}

// 复制文件方式二
public static void copyFile_2()
{
FileWriter fw = null;
FileReader fr = null;
try
{
// 创建文件写入的目的地
fw = new FileWriter("d:/copyFile_2.txt");
// 创建需要复制文件并关联
fr = new FileReader("d:/copyFile.txt");
//加入数组缓冲
char[] buf = new char[1024];
//开始读写数据
for(int len=0; (len=fr.read(buf))!=-1;)
{
fw.write(buf,0,len);
}
}
catch(IOException e)
{
throw new RuntimeException("读取文件失败。");
}
finally
{
if(fw!=null)
try
{
fw.close();
}
catch(IOException e)
{
throw new RuntimeException("写入流关闭失败");
}
if(fr!=null)
try
{
fr.close();
}
catch(IOException e)
{
throw new RuntimeException("读取流关闭失败。");
}
}

}
}


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


缓冲区,用于提高读取效率的流。
创建缓冲区之前,必须先有流对象。


缓冲技术的原理就是内部封装了数组。


如果一个饮水机坏了,开关只能一滴一滴的滴水,这个时候想喝水就很麻烦。
当然也可以直接用嘴巴去开关那里接,不过这样喝水很痛苦,如果这里用一个杯子
放在开关那里接水,接满以后再喝,这样就方便多了。这里的杯子就相当于缓冲区。


BufferedWriter没有空参数的构造方法,因为是为了提高流的读取效率,所以他出现
之前就已经有流对象了。所以也就没有空参数的。


BufferedWriter是FileWriter的子类。
只要用到缓冲区就得刷新,flush();
关闭缓冲区就是在关闭缓冲区中的流对象。


缓冲区中有一个跨平台,跨操作系统换行符写法 newLine();


缓冲区是在内存里面的。




/*
 写入缓冲区BufferedWriter
 */
package com.io;
import java.io.*;
public class BufferedWriterDemo
{
public static void main(String[] args)
{
FileWriter fw = null;
BufferedWriter bw = null;
try
{
// 创建写入流对象
fw = new FileWriter("e:/demo.txt",true);
// 加入缓冲区技术以提高写入的效率,把需要被缓冲的fw对象加入即可
bw = new BufferedWriter(fw);
// BufferedWriter继承于FileWriter,所以可以用fileWriter里面的方法
for(int x=0; x<10; x++)
{
// 把数据读到流里面去
bw.write("dajfdkajffjdak");
//跨平台换行符
bw.newLine();
// 把数据刷新,刷到目的地文件里面去。
bw.flush();
}
}
catch(IOException e)
{
throw new RuntimeException("写入数据失败");
}
finally
{
if(bw!=null)
try
{
bw.close();
}
catch(IOException e)
{
throw new RuntimeException("关闭缓冲区写入流失败");
}
}

}
}


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


字符读取流缓冲区:
一般在实际的开发中都要加入缓冲区技术以提高效率。




/*
 字符读取流缓冲区:BufferedReader可以读取一行的方法
 readLine返回null表示读到文件末尾
 */
package com.io;
import java.io.*;
public class BufferedReaderDemo
{
public static void main(String[] args)
{
FileReader fr = null;
BufferedReader bufr = null;
try
{
// 创建一个读取流对象,并且关联被读取的文件
fr = new FileReader("E:/demo.txt");
// 加入缓冲区以提高效率
bufr = new BufferedReader(fr);
// 开始读数据
for(String line=null; (line=bufr.readLine())!=null;)
System.out.println(line);
}
catch(IOException e)
{
throw new RuntimeException("文件读取失败");
}
finally
{
if(bufr!=null)
try
{
bufr.close();
}
catch(IOException e)
{
throw new RuntimeException("读取流关闭失败");
}
}
}
}
--------------------------------------------------------------------------------------------
使用缓冲区复制文件


/*
 缓冲区复制文件 
 */
package com.io;
import java.io.*;
public class BufferedCopyFileDemo
{


public static void main(String[] args)
{
// 创建读取与写入流缓冲区引用
BufferedReader br = null;
BufferedWriter bw = null;
try
{
// 创建读取与写入流缓冲区对象
br = new BufferedReader(new FileReader("e:/demo.txt"));
bw = new BufferedWriter(new FileWriter("d:/demo.txt"));
// 开始读写数据
for(String readLine=null;(readLine=br.readLine())!=null;)
{
bw.write(readLine);
bw.newLine();
bw.flush();
}
}
catch(IOException e)
{
throw new RuntimeException("文件读写失败");
}
finally
{
if(br!=null)
try
{
br.close();
}
catch(IOException e)
{
throw new RuntimeException("读取流关闭失败");
}
if(bw!=null)
try
{
bw.close();
}
catch(IOException e)
{
throw new RuntimeException("写入流关闭失败");
}
}
}
}
----------------------------------------------------------------------------------------------


readLine方法原理


无论是读一行还是读取多个字符,最终都是在硬盘上一个一个的读取,
最终使用还是read方法,一次读一个的方法。


windows换行是两个字符 \r\n
意思就是说读到了回车换行符 \r\n 就算是读完一行。


/*
  模仿Buffered缓冲区做一个自己的MyBuffered
 */
package com.io;
import java.io.*;
public class MyBufferedDemo
{
private FileReader fr;
MyBufferedDemo(FileReader fr)
{
this.fr=fr;
}
// 缓冲区读取流
public  String myReadLine()throws IOException
{
// 定义临时容器
StringBuilder sb = new StringBuilder();
for(int ch=0; (ch=fr.read())!=-1;)
{
if(ch=='\r')
continue;
if(ch=='\n')
return sb.toString();
else
sb.append((char)ch);
}

if(sb.length()!=0)
return sb.toString();
return null;
}
// 关闭资源
public void myClose()throws IOException
{
fr.close();
}
public static void main(String[] args)
{
// 创建读取流引用 
FileReader fr = null;
MyBufferedDemo mbd = null;
try
{
// 创建读取流对象
fr = new FileReader("e:/demo.txt");
mbd = new MyBufferedDemo(fr);
// 开始读数据 
for(String line=null; (line=mbd.myReadLine())!=null;)
{
System.out.println(line);
}
}
catch(IOException e)
{
throw new RuntimeException("读取文件失败");
}
finally
{
if(mbd!=null)
try
{
mbd.myClose();
}
catch(IOException e)
{
throw new RuntimeException("文件读取流关闭失败");
}
}
}
}




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


装饰设计模式:大众化理解就是包装。也可以叫包装设计模式。
当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入
基于已有的功能,并提供加强功能,那么自定义的该类,就称为装饰类


说简单点就是给其他加强一些功能而已,所以在增强的时候只要把需要增强的类
传递给装饰类就可以了。


装饰类通常会通过构造方法接收被装饰的对象,并基于被装饰的对象,提供更强的功能。
装饰类通常是被装饰类的子类或者与被装饰类属于同一个体系中,属于同一个父类。


这样就把继承结构变成了组合结构了。






/*
 装饰设计模式
 */
package com.io;
import java.io.*;
//装饰类
public class DecorateDsignDemo
{
private Person p;
DecorateDsignDemo(Person p)
{
this.p=p;
}
public void employ()
{
// 被装饰类原有方法或者功能
p.clothing();
// 对原有功能增强
System.out.println("面试时,可以把服装穿得亮丽一些");
System.out.println("打领带");
System.out.println("穿皮鞋");

}
public static void main(String[] args)
{
Person p = new Person();
// 把被装饰的类通过构造方法传入
DecorateDsignDemo d = new DecorateDsignDemo(p);
d.employ();

}
}


//被装饰的类
class Person
{
public void clothing()
{
System.out.println("平时穿衣服,简单");
}
}


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


装饰设计模式与继承的区别:


装饰设计模式比继承要灵活,避免了继承体系的臃肿,而且降低了类与类之间的关系,


装饰类因为要增强已有对象,具备的功能和已有的是相同的,只不过提供了更强的功能。
所以装饰类和被装饰类通常都属于一个体系中的






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


LineNumberReader就是一个包装类,是一个带行号的包装类


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


字符流:
FileReader FileWriter


BufferedReader BufferedWriter


字节流:
InputStream 读,OutputStream,写。


字节流写入流不具备刷新功能。


字节流复制媒体文件不好,处理文字数据比较合适。




复制一张图片




/*
 复制一张图片
 */
package com.io;
import java.io.*;
public class CopyPictrueDemo
{
public static void main(String[] args)
{
// 创建字节流写入引用与读取引用
FileOutputStream fos = null;
FileInputStream fis = null;
try
{
// 创建字节流写入与读取流对象
fos = new FileOutputStream("e:/5.jpg");
fis = new FileInputStream("d:/5.jpg");
// 截取读写
byte[] buf = new byte[1024];

for(int len=0; (len=fis.read(buf))!=-1;)
{
fos.write(buf,0,len);
}
}
catch(IOException e)
{
throw new RuntimeException("文件读写失败");
}
finally
{
if(fos!=null)
try
{
fos.close();
}
catch(IOException e)
{
throw new RuntimeException("写入流关闭失败");
}
if(fis!=null)
try
{
fis.close();
}
catch(IOException e)
{
throw new RuntimeException("读取流关闭失败");
}
}
}
}












/*
 缓冲区复制媒体视频文件
 */
package com.io;
import java.io.*;
public class CopyMediaDemo
{


public static void main(String[] args)
{
long start = System.currentTimeMillis();
copyMedia();
long end = System.currentTimeMillis();
System.out.println(end-start);
}
public static void copyMedia()
{
// 创建字节流缓冲区的两个引用
BufferedOutputStream bos = null;
BufferedInputStream bis = null;

try
{
// 创建字节流缓冲区的两个读取与写入流对象
bos = new BufferedOutputStream(new FileOutputStream("d:/3.avi"));
bis = new BufferedInputStream(new FileInputStream("e:/2.avi"));
// 开始读写
for(int len=0; (len=bis.read())!=-1;)
{
bos.write(len);
}
}
catch(IOException e)
{
throw new RuntimeException("文件读写失败");
}
finally
{
try
{
if(bos!=null)
bos.close();
}
catch(IOException e)
{
throw new RuntimeException("字节写入流关闭失败");
}

try
{
if(bis!=null)
bis.close();
}
catch(IOException e)
{
throw new RuntimeException("字节读取流关闭失败");
}
}


}


}


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






键盘录入,
System.out  对应的是标准的输出设备,控制台。
System.in  对应标准的输入设备,键盘。


read方法是一个阻塞式方法,没有数据就等待。


'\r' 在ASCII表里是13,'n'是10






读取转换流:InputStreamReader;把字节流转换成字符流。


写入转换流:OutputStreamWriter,把字符流转换成字节流。






键盘录入最常见写法:
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));


/*
  键盘输入输出:inputStreamReader 与outputStreamWriter
 */
package com.io;
import java.io.*;
public class InputStreamReaderDemoAndOutputStreamWriter
{
public static void main(String[] args)throws IOException
{

systemOutDemo();
}
// 键盘录入
public static void systemInDemo()throws IOException
{
BufferedReader br = 
new BufferedReader(new InputStreamReader(System.in));
for(String line=null;(line=br.readLine())!=null;)
{
if("over".equals(line))
break;
System.out.println(line.toUpperCase());
}
}

// 键盘输出
public static void systemOutDemo()throws IOException
{
BufferedReader br = 
new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = 
new BufferedWriter(new OutputStreamWriter(System.out));
for(String line=null;(line=br.readLine())!=null;)
{
if("over".equals(line))
break;
bw.write(line.toUpperCase());
bw.newLine();
bw.flush();
}
}
}


流操作的基本规律:

1.明确源和目的。
源:输入流,InputStream  Reader
目的:输出流。OutputStream  Writer


2.操作的数据是否是纯文本。
是:字符流,不是,字节流。


3.当明确体系后,再明确使用哪个具体的对象。
通过设备来进行区分,
源设备:内存,硬盘,键盘。
目的设备:内存,硬盘,控制台。






需求演示:


1.将一个文本文件中的数据储存到另一个文件中,复制文件。
源:因为是源,所以使用读取流,InputStream Reader
是否文本文件?是,可以选择Reader,这时体系就明确了。


明确体系中的哪个对象?
明确设备:硬盘上的一个文件
Reader体系中可以操作文件的对象FileReader

是否需要提高效率?是,加入Reader体系中的缓冲区技术BufferedReader


FileReader fr = new FileReader("a.txt");
BufferedReader br = new BufferedReader(fr);


目的:OutputStream Writer
是否纯文本?是,Writer。
明确设备:硬盘上的一个文件。
Writer体系中可以操作文件的对象FileWriter

是否需要提高效率?是,加入Writer体系中的缓冲区技术BufferedWriter


FileWriter fw = new FileWriter("b.txt");
BufferedWriter bw = new BufferedWriter(fw);






需求:将键盘录入的数据保存到一个文件中。
这个需求的有源和目的都存在,分析
源:InputStream Reader 
是否纯文本?是,Reader

设备:键盘,对应的对象是System.in。
不是选择Reader吗?System.in对应的不是字节流吗?为了操作键盘的文本数据方便,
这时需要转换成字符流按照字符串操作是最方便的,所以,既然明确了Reader,那么就将
System.in转换成Reader。就用到了Reader体系中的转换流,InputStreamReader


InputStreamReader isr = new InputStreamReader(System.in);
需要提高效率吗?需要,BufferedReader,
BufferedReader br = new BufferedReader(isr);


目的:OutputStream Writer
是否是纯文本?是,Writer。
设备:硬盘上的一个文件,使用 FileWriter。
FileWriter fw = new FileWriter("c.txt");
需要提高效率吗?需要,BufferedWriter,
BufferWriter bufw = new BufferedWriter(fw);

扩展:想要把录入的数据按照指定的编码表(UTF-8),将数据存到文件中。


OutputStream Writer
是否是纯文本?是,Writer。
设备:硬盘上的一个文件,使用 FileWriter。


但是FileWriter是使用默认编码表,GBK。可是存储时,需要加入指定编码表
UTF-8 。而指定的编码表只有转换流可以指定,所以要使用的对象是OutputStreamWriter
而该转换流对象要接收一个字节输出流,而且还可以操作的文件的字节输出流,FileOutputStream

OuputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d.txt"),"UTF-8");


提高效率,BufferedWriter bufw = new BufferedWriter(osw);


记住,转换流什么时候使用,字符和字节之间的的桥梁,通常涉及到字符编码转换时,需要用到转换流。




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


File类


用于操作文件和文件夹的类。


File.separator()跨平台的目录分隔符。


File常见方法:


1.创建
在指定位置创建文件,如果该文件已经存在,则不创建,返回false.
和输出流不一样,输出流对象一建立就创建文件,而且会覆盖原来的文件。
boolean creatNewFile();

创建文件夹,和创建多级文件夹
boolean mkdir(); boolean mkdirs();


2.删除


boolean delete();删除失败返回false
void deleteOnExit();在程序退出时删除指定文件
3.判断。
在判断文件对象是文件还是目录的时候,先用exists()判断文件是否存在。
文件是否存在 boolean exists();
boolean isFile();是否是文件。
bollean isDirectory(); 是否是目录。
boolean isHidden();是不是隐藏文件。
boolean isABsolutePath()是否是绝对路径。



4.获取信息。
getName();获取名称,
getPath();获取路径,
getParent();获取父目录
getAbsolutePath()获取绝对路径。
lastModified()最好一次修改的时间。
length()长度。






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


 Properties 类的学习
 * Properties 是Hashtable的子类,也就是说具备Map集合的特点,
 * 而且它里面存储的键值对都是字符串。是集合与IO技术的相结合的一个综合容器
 * 该对象的特点在于 ,可以用于键值以形式的配置文件
 * 那么在加载数据时,需要数据具备固定的格式:键=值
 * 如:lishi=213
 * wangwu=23
--------------------------------------------------------------------------






一个接口没有方法,是属于标记接口。




 打印流:PrintStream:




字符输出流,很常用。PrintWriter:
构造函数:
1.file对象,File
2.字符串路径。String
3.字节输出流。OutputStream
4.字符输出流。Writer




SequenceInputStream,对象序列化,也就序列流,
常见的应用,比如文件的分割与合并。把多个流连接,或者把一个流分割。




ObjectOuputStream 对象流,对象的持久化存储,存储到一个文件中。


Serializable接口,实现这个接口类,才能被序列化,这个接口没有方法。
一个接口没有方法,是属于标记接口。


UID是给类的一个固定标识,


transient 关键字,被修饰的成员不会被序列化。




管道流: PipedInputStream  PipedOutputStream


RandomAccessFile:随机访问文件,这个类很特殊,集读写功能于一身。
但有一个局限性就是只能操作文件。数据分段,最好是有规律。
读写都可以。不是IO体系中的成员,直接继承自Object。
内部封装了一个数组,通过指针对数组中的元素操作,可以通过getFilePointer
获取指针的位置,同时可以通过seek改变指针的位置。skipBytes可以跳过多少个
指针,但不能往回走,而seek可以往回走。




他能完成读写的原理,内部封装了字节输入流和输出流。


通过构造函数可以看出,该类只能操作文件,而且操作文件还有模式,只读r 读写rw。
如果模式为只读,r,不会创建文件,会去读取一个已经存在的文件,如果文件不存在,
会出现异常,如果模式为rw那么,而且该对象的构造函数要操作的文件不存在,会自动创建,如果存在则不会覆盖。


多线程下载就可以用到这个类去实现。


如果写int类基本数据类型,建议使用writeInt这个方法,如果使用write方法会丢失数据。
因为write方法只写最低8位,也就是一个字节,丢3个了。而writeInt而则是把8个字节全部写出去。
一个中文是两个字节。
而且该对象的构造函数要操作的文件不存在,会自动创建,如果存在,则不会覆盖原有文件。
如果只读r,不会创建文件,会去读取一个已存在文件,如果该文件不存在,则会出现异常。
如果模式为rw,操作的文件不存在,会自动创建,如果存在则不会覆盖。




迅雷下载原理,就是可以用多线程和这个类来实现。
因为这个类可以分段写入数据,所以,多个线程可以同时分段的进行数据的写入,也就是
下载的原理。






一个中文汉字两个字节,一个字节等于八个二进行位。


DataInputStream and DataOutputStream  操作基本数据类型的流对象。


ByteArrayInputStream  and ByteArrayOutputStream


ByteArrayInputStream 在构造的时候,需要接收数据源,原是一个字节数组。
ByteArrayOutputStream 在构造的时候,不用定义数据目的,因为该对象中已经在内部封装
了可变的字节数组。这就是数据的目的地。


因为这两个流对象都操作的数组,并没有使用系统资源,所以,不用进行close()关闭


在流操作规律讲解时:
源设备,键盘,System.in 硬盘,FileStream 内存 ArrayStream

目的设备, 控制台,System.out 硬盘,FileStream 内存 ArrayStream


用流的读写思想来操作数组。


UTF-8是目前全世界通用的编码表,是unicode的优化形式。


编码:字符串变成字节数组。


解码:字节数组变成字符串


String-->byte[];  str.getBytes(charsetName);//指定编码。


byte[]-->String; new String(byte[] ,charsetName);




把数据存储到文件中,就是编码;用记事本打开文件就是解码。


package com.io;


import java.util.Arrays;


public class CodeDemo
{
public static void main(String[] args)throws Exception
{
String str = "天天 向上";
byte[] by = str.getBytes("GBK");//按GBK码表编码

// 按照GBK编码表解码。因为编码的时候是按照GBK编码的。
// 也就是说编码和解码的编码表要一样,否则就会出错。
// System.out.println(new String(by,"GBK"));//按GBK码表解码

// 如果解码的码表是ISO8859-1,而编码的码表是GBK,两个编解的码表不一样
// 这时可以按照以下方法通过再次编码解决
str = new String(by,"ISO8859-1");
// 对str2再次编码
byte[] by2 = str.getBytes("ISO8859-1");
// System.out.println(Arrays.toString(by2));//数组变成字符串

// 再次按照GBK解码
String s2 = new String(by2,"GBK");
System.out.println(s2);
// System.out.println(Arrays.toString(by));//数组变成字符串
}
}






8个二进制位等于一个字节。


联通,两个字会出现编码错误,那是因为UTF-8与GBK的编码冲突,是底层的二进制
出现的问题。








































































































































































































































































































































属于IO包
Reader 往外读,Writer往里写。
读数据就像读报纸,写数据就像写字。都得有对象,比如读报纸,先得有报纸
而写字也是一样,至少有一个地方让你写。比如写在纸上。


字符流的对象中融合了编码表,一般用于处理文字,文本文件。
而字节流用于处理媒体文件,比如图片,视频。。。
字符流是基本字节流的,媒体文凭和文本文件都可以处理
所以说字节流是通用的。


IO流常见操作就是操作文件。


/*
 演示IO流的FileWriter
 */
package com.io;
import java.io.*;
public class FileWriterDemo
{
public static void main(String[] args) throws IOException
{
// 创建一个文件用于存放写入的数据,如果该文件已经存在就覆盖。
FileWriter fw = new FileWriter("e:/dmeo.txt");
fw.write("dajflkdafj");//向dmo.txt文件中写入数据
fw.flush();//刷新缓冲区中的数据到文件中去。
fw.close();//关闭文件流,但要先刷新一次。
}
}




---------------------------------------------------------------------------------
IO异常处理:


/*
 IO异常处理。
 */
package com.io;
import java.io.*;
public class IOExceptionDemo
{
public static void main(String[] args)
{
FileWriter fw = null;
try
{
fw = new FileWriter("e:/demo.txt");
fw.write("java cee");
fw.flush();
}
catch(IOException e)
{
System.out.println(e.toString());
}
finally
{
try
{
if(fw!=null)//关闭流之前一定要先判断一下对象是不是空指针。
fw.close();
}
catch(IOException e)
{
System.out.println(e.toString());
}
}
}
}


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


数据的续写,在原有的数据基础上再写数据。


windows系统中换行符 \r\n
Linux系统中换行符  \r




/*
 文件的续写
 */
package com.io;
import java.io.*;
public class FileContuneDemo
{
public static void main(String[] args)
{

FileWriter fw = null;
try
{
// 创建一个文件,是用来存放文件的目的地。
// true参数表示不覆盖已经存放的文件,并且把数据续写到文件的末尾
fw = new FileWriter("e:/demo.txt",true);
fw.write("\r\ndjalkfdjaoifejaifueaifuda");//并且换一行
}
catch(IOException e)
{
System.out.println(e.toString());
}
finally
{
try
{
if(fw!=null)
fw.close();
}
catch(IOException e)
{
System.out.println(e.toString());
}
}
}


}


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


文本文件的读取方式一:
读文件就像读报纸一样,先得有报纸,所以构造函数没有空参数的。


每个文件的结尾处都有一个标识用以区分不同的文件。
当read读到文件结尾处时就返回-1




package com.io;
import java.io.*;
public class FileReaderDemo
{


public static void main(String[] args)
{
FileReader fr = null;
try
{
fr = new FileReader("e:/demo.txt");
for(int ch=0;(ch=fr.read())!=-1;)
{
System.out.println("ch="+(char)ch);
}

}
catch(IOException e)
{
System.out.println(e.toString());
}
finally
{
try
{
if(fr!=null)
fr.close();
}
catch(IOException e)
{
System.out.println(e.toString());
}
}
}
}


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


文本文件的读取方式二:


读取字符数组,通过字符数组进行读取。


一个字符等于两个字节。


/*
 字符数组缓冲区读取文本文件
 */
package com.io;
import java.io.*;
public class CharReaderDemo
{
public static void main(String[] args)
{
FileReader fr = null;
try
{
// 创建文件读取流对象
fr = new FileReader("e:/demo.txt");
//加入字符数组缓冲区读取文本
char[] buf = new char[1024];
for(int num=0;(num=fr.read(buf))!=-1;)
{
System.out.println("buf"+new String(buf,0,num));
}
}
catch(IOException e)
{
System.out.println(e.toString());
}
finally
{
try
{
if(fr!=null)
fr.close();
}
catch(IOException e)
{
System.out.println(e.toString());
}
}
}
}




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




读取硬盘上的一个.java文件


/*
 读一个JAVA文件
 */
package com.io;
import java.io.*;
public class ReadJavaDemo
{
public static void main(String[] args)
{
FileReader fr = null;
try
{
fr = new FileReader("D:\\Workspaces\\MyEclipse 10\\TestProject\\src\\com\\io\\ReadJavaDemo.java");
// 加入数组缓冲区技术读取数据
char[] buf = new char[1024];
for(int num=0; (num=fr.read(buf))!=-1;)
System.out.println(new String(buf,0,num));
}
catch(IOException e)
{
System.out.println(e.toString());
}
finally
{
try
{
if(fr!=null)
fr.close();
}
catch(IOException e)
{
System.out.println(e.toString());
}
}
}


}
----------------------------------------------------------------------------------
将C盘的一个文本文件复制到D盘。
复制原理:
就是将C盘下的文件数据存储到D盘文件中


步骤:
1.在D盘创建一个文件,用于存储C盘文件中的数据
2.定义读取流和C盘文件关联
3.通过不断的读写完成数据存储
4.关闭资源






/*
 复制文件
 */
package com.io;
import java.io.*;
public class CopyFile
{
public static void main(String[] args)
{
copyFile_2();
// copyFile_1();
}
// 复制文件方式一
public static void copyFile_1()
{
FileWriter fw = null;
FileReader fr = null;
try
{
// 创建文件复制的目的地
fw = new FileWriter("d:/copyFile.txt");
// 创建需要复制的文件关联
fr = new FileReader("c:/RHDSetup.log");
for(int len=0; (len=fr.read())!=-1;)
{
fw.write(len);
}
}
catch(IOException e)
{
throw new RuntimeException("数据流读取失败");
}
finally
{
if(fw!=null)
try
{
fw.close();
}
catch(IOException e)
{
throw new RuntimeException("关闭写入流失败。");
}
if(fr!=null)
try
{
fr.close();
}
catch(IOException e)
{
throw new RuntimeException("读取流关闭失败");
}

}
}

// 复制文件方式二
public static void copyFile_2()
{
FileWriter fw = null;
FileReader fr = null;
try
{
// 创建文件写入的目的地
fw = new FileWriter("d:/copyFile_2.txt");
// 创建需要复制文件并关联
fr = new FileReader("d:/copyFile.txt");
//加入数组缓冲
char[] buf = new char[1024];
//开始读写数据
for(int len=0; (len=fr.read(buf))!=-1;)
{
fw.write(buf,0,len);
}
}
catch(IOException e)
{
throw new RuntimeException("读取文件失败。");
}
finally
{
if(fw!=null)
try
{
fw.close();
}
catch(IOException e)
{
throw new RuntimeException("写入流关闭失败");
}
if(fr!=null)
try
{
fr.close();
}
catch(IOException e)
{
throw new RuntimeException("读取流关闭失败。");
}
}

}
}


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


缓冲区,用于提高读取效率的流。
创建缓冲区之前,必须先有流对象。


缓冲技术的原理就是内部封装了数组。


如果一个饮水机坏了,开关只能一滴一滴的滴水,这个时候想喝水就很麻烦。
当然也可以直接用嘴巴去开关那里接,不过这样喝水很痛苦,如果这里用一个杯子
放在开关那里接水,接满以后再喝,这样就方便多了。这里的杯子就相当于缓冲区。


BufferedWriter没有空参数的构造方法,因为是为了提高流的读取效率,所以他出现
之前就已经有流对象了。所以也就没有空参数的。


BufferedWriter是FileWriter的子类。
只要用到缓冲区就得刷新,flush();
关闭缓冲区就是在关闭缓冲区中的流对象。


缓冲区中有一个跨平台,跨操作系统换行符写法 newLine();


缓冲区是在内存里面的。




/*
 写入缓冲区BufferedWriter
 */
package com.io;
import java.io.*;
public class BufferedWriterDemo
{
public static void main(String[] args)
{
FileWriter fw = null;
BufferedWriter bw = null;
try
{
// 创建写入流对象
fw = new FileWriter("e:/demo.txt",true);
// 加入缓冲区技术以提高写入的效率,把需要被缓冲的fw对象加入即可
bw = new BufferedWriter(fw);
// BufferedWriter继承于FileWriter,所以可以用fileWriter里面的方法
for(int x=0; x<10; x++)
{
// 把数据读到流里面去
bw.write("dajfdkajffjdak");
//跨平台换行符
bw.newLine();
// 把数据刷新,刷到目的地文件里面去。
bw.flush();
}
}
catch(IOException e)
{
throw new RuntimeException("写入数据失败");
}
finally
{
if(bw!=null)
try
{
bw.close();
}
catch(IOException e)
{
throw new RuntimeException("关闭缓冲区写入流失败");
}
}

}
}


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


字符读取流缓冲区:
一般在实际的开发中都要加入缓冲区技术以提高效率。




/*
 字符读取流缓冲区:BufferedReader可以读取一行的方法
 readLine返回null表示读到文件末尾
 */
package com.io;
import java.io.*;
public class BufferedReaderDemo
{
public static void main(String[] args)
{
FileReader fr = null;
BufferedReader bufr = null;
try
{
// 创建一个读取流对象,并且关联被读取的文件
fr = new FileReader("E:/demo.txt");
// 加入缓冲区以提高效率
bufr = new BufferedReader(fr);
// 开始读数据
for(String line=null; (line=bufr.readLine())!=null;)
System.out.println(line);
}
catch(IOException e)
{
throw new RuntimeException("文件读取失败");
}
finally
{
if(bufr!=null)
try
{
bufr.close();
}
catch(IOException e)
{
throw new RuntimeException("读取流关闭失败");
}
}
}
}
--------------------------------------------------------------------------------------------
使用缓冲区复制文件


/*
 缓冲区复制文件 
 */
package com.io;
import java.io.*;
public class BufferedCopyFileDemo
{


public static void main(String[] args)
{
// 创建读取与写入流缓冲区引用
BufferedReader br = null;
BufferedWriter bw = null;
try
{
// 创建读取与写入流缓冲区对象
br = new BufferedReader(new FileReader("e:/demo.txt"));
bw = new BufferedWriter(new FileWriter("d:/demo.txt"));
// 开始读写数据
for(String readLine=null;(readLine=br.readLine())!=null;)
{
bw.write(readLine);
bw.newLine();
bw.flush();
}
}
catch(IOException e)
{
throw new RuntimeException("文件读写失败");
}
finally
{
if(br!=null)
try
{
br.close();
}
catch(IOException e)
{
throw new RuntimeException("读取流关闭失败");
}
if(bw!=null)
try
{
bw.close();
}
catch(IOException e)
{
throw new RuntimeException("写入流关闭失败");
}
}
}
}
----------------------------------------------------------------------------------------------


readLine方法原理


无论是读一行还是读取多个字符,最终都是在硬盘上一个一个的读取,
最终使用还是read方法,一次读一个的方法。


windows换行是两个字符 \r\n
意思就是说读到了回车换行符 \r\n 就算是读完一行。


/*
  模仿Buffered缓冲区做一个自己的MyBuffered
 */
package com.io;
import java.io.*;
public class MyBufferedDemo
{
private FileReader fr;
MyBufferedDemo(FileReader fr)
{
this.fr=fr;
}
// 缓冲区读取流
public  String myReadLine()throws IOException
{
// 定义临时容器
StringBuilder sb = new StringBuilder();
for(int ch=0; (ch=fr.read())!=-1;)
{
if(ch=='\r')
continue;
if(ch=='\n')
return sb.toString();
else
sb.append((char)ch);
}

if(sb.length()!=0)
return sb.toString();
return null;
}
// 关闭资源
public void myClose()throws IOException
{
fr.close();
}
public static void main(String[] args)
{
// 创建读取流引用 
FileReader fr = null;
MyBufferedDemo mbd = null;
try
{
// 创建读取流对象
fr = new FileReader("e:/demo.txt");
mbd = new MyBufferedDemo(fr);
// 开始读数据 
for(String line=null; (line=mbd.myReadLine())!=null;)
{
System.out.println(line);
}
}
catch(IOException e)
{
throw new RuntimeException("读取文件失败");
}
finally
{
if(mbd!=null)
try
{
mbd.myClose();
}
catch(IOException e)
{
throw new RuntimeException("文件读取流关闭失败");
}
}
}
}




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


装饰设计模式:大众化理解就是包装。也可以叫包装设计模式。
当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入
基于已有的功能,并提供加强功能,那么自定义的该类,就称为装饰类


说简单点就是给其他加强一些功能而已,所以在增强的时候只要把需要增强的类
传递给装饰类就可以了。


装饰类通常会通过构造方法接收被装饰的对象,并基于被装饰的对象,提供更强的功能。
装饰类通常是被装饰类的子类或者与被装饰类属于同一个体系中,属于同一个父类。


这样就把继承结构变成了组合结构了。






/*
 装饰设计模式
 */
package com.io;
import java.io.*;
//装饰类
public class DecorateDsignDemo
{
private Person p;
DecorateDsignDemo(Person p)
{
this.p=p;
}
public void employ()
{
// 被装饰类原有方法或者功能
p.clothing();
// 对原有功能增强
System.out.println("面试时,可以把服装穿得亮丽一些");
System.out.println("打领带");
System.out.println("穿皮鞋");

}
public static void main(String[] args)
{
Person p = new Person();
// 把被装饰的类通过构造方法传入
DecorateDsignDemo d = new DecorateDsignDemo(p);
d.employ();

}
}


//被装饰的类
class Person
{
public void clothing()
{
System.out.println("平时穿衣服,简单");
}
}


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


装饰设计模式与继承的区别:


装饰设计模式比继承要灵活,避免了继承体系的臃肿,而且降低了类与类之间的关系,


装饰类因为要增强已有对象,具备的功能和已有的是相同的,只不过提供了更强的功能。
所以装饰类和被装饰类通常都属于一个体系中的






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


LineNumberReader就是一个包装类,是一个带行号的包装类


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


字符流:
FileReader FileWriter


BufferedReader BufferedWriter


字节流:
InputStream 读,OutputStream,写。


字节流写入流不具备刷新功能。


字节流复制媒体文件不好,处理文字数据比较合适。




复制一张图片




/*
 复制一张图片
 */
package com.io;
import java.io.*;
public class CopyPictrueDemo
{
public static void main(String[] args)
{
// 创建字节流写入引用与读取引用
FileOutputStream fos = null;
FileInputStream fis = null;
try
{
// 创建字节流写入与读取流对象
fos = new FileOutputStream("e:/5.jpg");
fis = new FileInputStream("d:/5.jpg");
// 截取读写
byte[] buf = new byte[1024];

for(int len=0; (len=fis.read(buf))!=-1;)
{
fos.write(buf,0,len);
}
}
catch(IOException e)
{
throw new RuntimeException("文件读写失败");
}
finally
{
if(fos!=null)
try
{
fos.close();
}
catch(IOException e)
{
throw new RuntimeException("写入流关闭失败");
}
if(fis!=null)
try
{
fis.close();
}
catch(IOException e)
{
throw new RuntimeException("读取流关闭失败");
}
}
}
}












/*
 缓冲区复制媒体视频文件
 */
package com.io;
import java.io.*;
public class CopyMediaDemo
{


public static void main(String[] args)
{
long start = System.currentTimeMillis();
copyMedia();
long end = System.currentTimeMillis();
System.out.println(end-start);
}
public static void copyMedia()
{
// 创建字节流缓冲区的两个引用
BufferedOutputStream bos = null;
BufferedInputStream bis = null;

try
{
// 创建字节流缓冲区的两个读取与写入流对象
bos = new BufferedOutputStream(new FileOutputStream("d:/3.avi"));
bis = new BufferedInputStream(new FileInputStream("e:/2.avi"));
// 开始读写
for(int len=0; (len=bis.read())!=-1;)
{
bos.write(len);
}
}
catch(IOException e)
{
throw new RuntimeException("文件读写失败");
}
finally
{
try
{
if(bos!=null)
bos.close();
}
catch(IOException e)
{
throw new RuntimeException("字节写入流关闭失败");
}

try
{
if(bis!=null)
bis.close();
}
catch(IOException e)
{
throw new RuntimeException("字节读取流关闭失败");
}
}


}


}


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






键盘录入,
System.out  对应的是标准的输出设备,控制台。
System.in  对应标准的输入设备,键盘。


read方法是一个阻塞式方法,没有数据就等待。


'\r' 在ASCII表里是13,'n'是10






读取转换流:InputStreamReader;把字节流转换成字符流。


写入转换流:OutputStreamWriter,把字符流转换成字节流。






键盘录入最常见写法:
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));


/*
  键盘输入输出:inputStreamReader 与outputStreamWriter
 */
package com.io;
import java.io.*;
public class InputStreamReaderDemoAndOutputStreamWriter
{
public static void main(String[] args)throws IOException
{

systemOutDemo();
}
// 键盘录入
public static void systemInDemo()throws IOException
{
BufferedReader br = 
new BufferedReader(new InputStreamReader(System.in));
for(String line=null;(line=br.readLine())!=null;)
{
if("over".equals(line))
break;
System.out.println(line.toUpperCase());
}
}

// 键盘输出
public static void systemOutDemo()throws IOException
{
BufferedReader br = 
new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = 
new BufferedWriter(new OutputStreamWriter(System.out));
for(String line=null;(line=br.readLine())!=null;)
{
if("over".equals(line))
break;
bw.write(line.toUpperCase());
bw.newLine();
bw.flush();
}
}
}


流操作的基本规律:

1.明确源和目的。
源:输入流,InputStream  Reader
目的:输出流。OutputStream  Writer


2.操作的数据是否是纯文本。
是:字符流,不是,字节流。


3.当明确体系后,再明确使用哪个具体的对象。
通过设备来进行区分,
源设备:内存,硬盘,键盘。
目的设备:内存,硬盘,控制台。






需求演示:


1.将一个文本文件中的数据储存到另一个文件中,复制文件。
源:因为是源,所以使用读取流,InputStream Reader
是否文本文件?是,可以选择Reader,这时体系就明确了。


明确体系中的哪个对象?
明确设备:硬盘上的一个文件
Reader体系中可以操作文件的对象FileReader

是否需要提高效率?是,加入Reader体系中的缓冲区技术BufferedReader


FileReader fr = new FileReader("a.txt");
BufferedReader br = new BufferedReader(fr);


目的:OutputStream Writer
是否纯文本?是,Writer。
明确设备:硬盘上的一个文件。
Writer体系中可以操作文件的对象FileWriter

是否需要提高效率?是,加入Writer体系中的缓冲区技术BufferedWriter


FileWriter fw = new FileWriter("b.txt");
BufferedWriter bw = new BufferedWriter(fw);






需求:将键盘录入的数据保存到一个文件中。
这个需求的有源和目的都存在,分析
源:InputStream Reader 
是否纯文本?是,Reader

设备:键盘,对应的对象是System.in。
不是选择Reader吗?System.in对应的不是字节流吗?为了操作键盘的文本数据方便,
这时需要转换成字符流按照字符串操作是最方便的,所以,既然明确了Reader,那么就将
System.in转换成Reader。就用到了Reader体系中的转换流,InputStreamReader


InputStreamReader isr = new InputStreamReader(System.in);
需要提高效率吗?需要,BufferedReader,
BufferedReader br = new BufferedReader(isr);


目的:OutputStream Writer
是否是纯文本?是,Writer。
设备:硬盘上的一个文件,使用 FileWriter。
FileWriter fw = new FileWriter("c.txt");
需要提高效率吗?需要,BufferedWriter,
BufferWriter bufw = new BufferedWriter(fw);

扩展:想要把录入的数据按照指定的编码表(UTF-8),将数据存到文件中。


OutputStream Writer
是否是纯文本?是,Writer。
设备:硬盘上的一个文件,使用 FileWriter。


但是FileWriter是使用默认编码表,GBK。可是存储时,需要加入指定编码表
UTF-8 。而指定的编码表只有转换流可以指定,所以要使用的对象是OutputStreamWriter
而该转换流对象要接收一个字节输出流,而且还可以操作的文件的字节输出流,FileOutputStream

OuputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d.txt"),"UTF-8");


提高效率,BufferedWriter bufw = new BufferedWriter(osw);


记住,转换流什么时候使用,字符和字节之间的的桥梁,通常涉及到字符编码转换时,需要用到转换流。




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


File类


用于操作文件和文件夹的类。


File.separator()跨平台的目录分隔符。


File常见方法:


1.创建
在指定位置创建文件,如果该文件已经存在,则不创建,返回false.
和输出流不一样,输出流对象一建立就创建文件,而且会覆盖原来的文件。
boolean creatNewFile();

创建文件夹,和创建多级文件夹
boolean mkdir(); boolean mkdirs();


2.删除


boolean delete();删除失败返回false
void deleteOnExit();在程序退出时删除指定文件
3.判断。
在判断文件对象是文件还是目录的时候,先用exists()判断文件是否存在。
文件是否存在 boolean exists();
boolean isFile();是否是文件。
bollean isDirectory(); 是否是目录。
boolean isHidden();是不是隐藏文件。
boolean isABsolutePath()是否是绝对路径。



4.获取信息。
getName();获取名称,
getPath();获取路径,
getParent();获取父目录
getAbsolutePath()获取绝对路径。
lastModified()最好一次修改的时间。
length()长度。






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


 Properties 类的学习
 * Properties 是Hashtable的子类,也就是说具备Map集合的特点,
 * 而且它里面存储的键值对都是字符串。是集合与IO技术的相结合的一个综合容器
 * 该对象的特点在于 ,可以用于键值以形式的配置文件
 * 那么在加载数据时,需要数据具备固定的格式:键=值
 * 如:lishi=213
 * wangwu=23
--------------------------------------------------------------------------






一个接口没有方法,是属于标记接口。




 打印流:PrintStream:




字符输出流,很常用。PrintWriter:
构造函数:
1.file对象,File
2.字符串路径。String
3.字节输出流。OutputStream
4.字符输出流。Writer




SequenceInputStream,对象序列化,也就序列流,
常见的应用,比如文件的分割与合并。把多个流连接,或者把一个流分割。




ObjectOuputStream 对象流,对象的持久化存储,存储到一个文件中。


Serializable接口,实现这个接口类,才能被序列化,这个接口没有方法。
一个接口没有方法,是属于标记接口。


UID是给类的一个固定标识,


transient 关键字,被修饰的成员不会被序列化。




管道流: PipedInputStream  PipedOutputStream


RandomAccessFile:随机访问文件,这个类很特殊,集读写功能于一身。
但有一个局限性就是只能操作文件。数据分段,最好是有规律。
读写都可以。不是IO体系中的成员,直接继承自Object。
内部封装了一个数组,通过指针对数组中的元素操作,可以通过getFilePointer
获取指针的位置,同时可以通过seek改变指针的位置。skipBytes可以跳过多少个
指针,但不能往回走,而seek可以往回走。




他能完成读写的原理,内部封装了字节输入流和输出流。


通过构造函数可以看出,该类只能操作文件,而且操作文件还有模式,只读r 读写rw。
如果模式为只读,r,不会创建文件,会去读取一个已经存在的文件,如果文件不存在,
会出现异常,如果模式为rw那么,而且该对象的构造函数要操作的文件不存在,会自动创建,如果存在则不会覆盖。


多线程下载就可以用到这个类去实现。


如果写int类基本数据类型,建议使用writeInt这个方法,如果使用write方法会丢失数据。
因为write方法只写最低8位,也就是一个字节,丢3个了。而writeInt而则是把8个字节全部写出去。
一个中文是两个字节。
而且该对象的构造函数要操作的文件不存在,会自动创建,如果存在,则不会覆盖原有文件。
如果只读r,不会创建文件,会去读取一个已存在文件,如果该文件不存在,则会出现异常。
如果模式为rw,操作的文件不存在,会自动创建,如果存在则不会覆盖。




迅雷下载原理,就是可以用多线程和这个类来实现。
因为这个类可以分段写入数据,所以,多个线程可以同时分段的进行数据的写入,也就是
下载的原理。






一个中文汉字两个字节,一个字节等于八个二进行位。


DataInputStream and DataOutputStream  操作基本数据类型的流对象。


ByteArrayInputStream  and ByteArrayOutputStream


ByteArrayInputStream 在构造的时候,需要接收数据源,原是一个字节数组。
ByteArrayOutputStream 在构造的时候,不用定义数据目的,因为该对象中已经在内部封装
了可变的字节数组。这就是数据的目的地。


因为这两个流对象都操作的数组,并没有使用系统资源,所以,不用进行close()关闭


在流操作规律讲解时:
源设备,键盘,System.in 硬盘,FileStream 内存 ArrayStream

目的设备, 控制台,System.out 硬盘,FileStream 内存 ArrayStream


用流的读写思想来操作数组。


UTF-8是目前全世界通用的编码表,是unicode的优化形式。


编码:字符串变成字节数组。


解码:字节数组变成字符串


String-->byte[];  str.getBytes(charsetName);//指定编码。


byte[]-->String; new String(byte[] ,charsetName);




把数据存储到文件中,就是编码;用记事本打开文件就是解码。


package com.io;


import java.util.Arrays;


public class CodeDemo
{
public static void main(String[] args)throws Exception
{
String str = "天天 向上";
byte[] by = str.getBytes("GBK");//按GBK码表编码

// 按照GBK编码表解码。因为编码的时候是按照GBK编码的。
// 也就是说编码和解码的编码表要一样,否则就会出错。
// System.out.println(new String(by,"GBK"));//按GBK码表解码

// 如果解码的码表是ISO8859-1,而编码的码表是GBK,两个编解的码表不一样
// 这时可以按照以下方法通过再次编码解决
str = new String(by,"ISO8859-1");
// 对str2再次编码
byte[] by2 = str.getBytes("ISO8859-1");
// System.out.println(Arrays.toString(by2));//数组变成字符串

// 再次按照GBK解码
String s2 = new String(by2,"GBK");
System.out.println(s2);
// System.out.println(Arrays.toString(by));//数组变成字符串
}
}






8个二进制位等于一个字节。


联通,两个字会出现编码错误,那是因为UTF-8与GBK的编码冲突,是底层的二进制
出现的问题。









































































































































































































































































































































评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值