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的编码冲突,是底层的二进制
出现的问题。