IO
字符流和字节流
-字节流两个基类:
InputStream OutputStream
-字符流两个基类:
Reader Writer
既然IO流失用于操作数据的,那么数据的最常见体现形式是:文件。
那么先以操作文件为主来掩饰。
需求:在硬盘上,创建一个文件并写入一些文字数据。
找到一个专门用于操作文件的writer子类对象,FileWriter。后缀名是父类名。前缀名是该刘对象的功能。
FileWriter
import java.io.*;
public static void main(String[] args) throws IOException{
FileWriter fw=new FileWriter("demo.txt");
//创建一个FileWriter对象。该对象一杯初始化就必须要明确被操作的文件
//而且该文件会被创建到指定目录下。如果该目录下已有同名文件,将被覆盖。
fw.write(“dadfe”) //调用write方法,将字符串写入到流中
fw.flush(); //刷新流对象中的缓冲中德数据。 //将数据刷到目的地中
}
fw.close(); //关闭流资源,但是关闭之前会刷新一次内部的缓冲中的数据。将数据刷到目的地中。
close和flush区别:flush刷新后,流可以继续使用,close刷新偶,会将流关闭。
IO异常的处理方式。
FielWriter fw=null;
try{
fw=new FileWriter("demo.txt");
fw.write("adbetg");
fw.close();
}
catch(IOException e){
System.out.println(e.toString());
}
finally{
try{
if(fw!=null)
fw.close();}
catch(IOException e){
System.out.println(e.toString())
}
}
---------------------------------
FileWriter fw=new FileWriter("demo.txt",true) //传递一个true参数,代表不覆盖已有的文件。并在已有文件的末尾处进行数据续写
fw.write("haa");
\r\n 回车
FileReader
import java.io.*;
public static void main(String[] args) throws IOException{
FileReader fr=new FileReader("demo.txt")
//创建一个文件读取流对象,和制定名称的文件相关联。
//要保证该文件是已经存在的,如果不存在,会发生异常FileNotFoundException
//调用读取流对象的read
int ch=fr.read();
//定义一个字符数组。用于存储读到字符。
//该rea(char[])返回的是读到字符个数
char[] buf=new char[1024] ;
/*int num=fr.read(buf);
System.out.println(new String(buf))
int num1=fr.read(buf);
System.out.println(new String(buf,0,num1)) */
int num=0;
while((num=fr.read(buf))!=-1){
System.out.println(new String(buf,0,num))
}
fr.close();
}
第一种:read():读一个字符,而且会自动往下读。
读取的字符数,如果已到达流的末尾,则返回-1
第二种:通过字符数组进行读取。
import java.io.*;
class CopyText{
public static void main(String[] args)throws IOException{
}
//从c盘读一个字符,就往D盘写一个字符。
public static void copy_1()throws IOException{
//创建目的地。
FileWriter fw=new FileWriter("RuntimeDemo_copy.txt")
//与已有文件关联
FileReader fr=new FileReader("RuntimeDemo.java")
int ch=0;
while((ch=fr.read())!=-1){
fw.write(new String(ch));
}
fw.close();
fr.close();
}
public static void copy_2(){
FileWriter fw=null;
FileReader fr=null;
try{
fw=new FileWriter("SytemDemo_copy.txt")
fr=new FileReader("SytemDemo.java")
char[] buf=new char[1024];
int len=0
while((len=fr.read(buf))!=-1){
fw.write(buf,0,len)
}
}
catch(IOException e){
throw new RuntimeException("读写失败")
}
finally{
try{
if((fr.read())=null)
fr.close()
}
catch(IOException){
}
try{
if((fw.read())=null)
fw.close()
}
catch(IOException){
}
}
}
}
缓冲区
缓冲区的出现时为了提高流的操作效率而出现的。
所以在创建缓冲区之前,必须要先有流对象。
该缓冲区中提供了一个跨平台的换行符。newLine();用缓冲区对象才能用这个功能。
BufferWriter
//创建一个字符写入流对象。
FileWriter fw=new FileWriter("buf.txt")
//为了提高字符写入流效率,加入了缓冲技术,只要将需要房提高效率的流对象作为参数传递给缓冲区的构造函数即可。
BufferedWriter bufw=new BufferedWriter(fw)
bufw.write("abcde")
bufw.newLine(); //换行
//记住,只要用到缓冲区要刷新。
bufw.flush();
//其实关闭缓冲区,就是在关闭缓冲区中的流对象。
bufw.close();
BufferReader
//创建一个读书流对象和文件相关联。
FileReader fr=new FileReader("buf.txt");
//为了提高效率。加入缓冲技术。将字符读取流对象作为参数传递给缓冲对象
BufferReader bufr=new BufferedReader(fr);
String line=null
while((line=bufr.readLine())!=null){
System.out.println(line);
}
bufr.close();
字符读取流缓冲区:
该缓冲区提供了一个一次读一行的方法readLine,方法于对文本数据的获取。
当返回Null是,表示读到文件末尾。
readLine方法返回的时候只返回回车符之前的数据内容。并不返回回车符
readLine方法的原理:无论是毒一行,获取读获取多个字符。其实最终都是在硬盘上一个一个读取。所以最终使用的还是read方法一次读一个的方法。
装饰设计模式
当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入,基于已有的功能,并提供加强功能。
那么自定义的该类成为装饰类。
装饰类通常会通过构造方法接受被装饰的对象。
并基于被装饰的对象的功能,提供的更强的功能。
MyReader //专门用于读取数据的类
|--MyTextReader
|--MyBufferTextReader
|--MyMediaReader
|--MyBufferMediaReader
装饰类因为增强已有对象,具备的功能和已有的是相通的,只不过提供了更强功能。所以装饰类和被装饰类通常是都属于一个体系中的
class MyBufferReader extends MyReader{
private MyReader r;
MyBufferReader(MyReader r){
}
}
LineNumberReader inr=new LinNumberReader(fr)
String line=null;
while((line=lnr.readLine())!=null){
System.out.println(lnr.getLineNumber())
}
----------------------------------下面是显示linenumber行号
private Reader r;
private int lineNumber;
MyLineNumberReader(Reader r){
this.r=r;
}
public String MyLineNumberReader() throws IOException{
StringBuilder sb=new StringBuilder();
int ch=0;
while((ch=r.read())!=0){
if(ch=='\r')
continue;
if(ch=='\n')
retrun sb.toString();
else
sb.append((char)ch);
}
if(sb.length()!=0)
return sb.toString();
return null;
publci int setLineNumber(){
this.lineNumber=lineNumber;
}
publci int getLineNumber(){
return lineNumber;
}
public void myClose()Throws IOException{
r.close();
}
}
publci static void main(String[] args) throws IOException
{
FileReader fr=new FileReader("");
MyReadLine my=new MyReadLine(fr);
String line=null;
while((line=my.myRedLine())!=null)
{
System.outj.println(my.getLineNumber()+"::"line);
}
}
--------------- 第二种
class MyLineNumberReader extends MyBufferedReader
{
private int lineNumber;
MyLineNumberReader(Reader r){
super(r);
}
public String MyLineNumberReader() throws IOException{
linenumber++;
return super.myReadLine();
publci int setLineNumber(){
this.lineNumber=lineNumber;
}
publci int getLineNumber(){
return lineNumber;
}
}
publci static void main(String[] args) throws IOException
{
FileReader fr=new FileReader("");
MyReadLine my=new MyReadLine(fr);
String line=null;
while((line=my.myRedLine())!=null)
{
System.outj.println(my.getLineNumber()+"::"line);
}
}
字节流
public static void writeFile(){
FileOutputStream fos=new FileOutputStream("fos.txt ")
fos.write("abcde".getBytes() //字符串-字符数组 반대.toCharArray();
fos.close(); //关闭资源
}
----1
public static void readFile(){
FileInputStream fis=new FileInputStream("fos.txt")
int ch=null
while((ch=fis.read())!=-1){
System.out.println((char)ch)
}
}
----2
public static void readFile(){
FileInputStream fis=new FileInputStream("fos.txt");
byte[] buf=new byte[1024]
int len=0;
while((len=fis.read(buf))!=-1){
fis.write(buf,0,len)
}
}
---3 //字节流特有的
public static void readFile(){
FileInputStream fis=new FileInputStream("fos.txt");
int num=fis.available(); //个数
byte[] buf=new byte[num];
fis.write(buf)
System.out.println(new String(buf));
fis.close();
}
------
class MyBufferedInputStream
{
private InputStream in;
private byte[] buf=new byte[1024];
private int pos=0,count=0;
MyBufferedInputStream(InputStream in) throws IOException{
this.in=in;
}
public int myRead(){
if(count==0)
{
count=in.read(buf);
if(count<0)
return -1;
pos=0;
byte b=buf[pos];
count--;
pos++;
return b&255;
}
else if(count>0){
byte b=buf[pos];
count--;
pos++;
return b&255;
}
}
字符流:FileReader FileWriter
BufferedReader BufferedWriter
字节流:FileInputStream FileOutputStream
BufferedInputStream BufferedOutputStream
读取键盘录入
System.out:对应的是标准输出设备,控制台
System.in:对应的标准输入设备:键盘 ------InputStream
需求:
通过键盘录入数据。
当录入一行数据后,就将该行数据进行打印。
如果录入的数据是over,那么停止录入
InputStream in=System.in;
StringBuilder sb=new StringBuilder();
while(true){
int by=in.read();
if(ch=='\r)
continue;
if(ch=="\n')
{
String s=sb.toString();
if("over".equals(s))
break;
System.out.println(s.toUpperCase());
sb.delete(0,sb.length())
}
else
sb.append((char)ch);
}
InputStreamReader
字节流通向字符流的桥梁
通过刚才的键盘录入一行数据并打印其大写,发现其实就是读一行数据的原理。也就是readLine方法。
能不能直接使用readLine方法来完成键盘录入的一行数据的读取呢?
readLine方法是字符流BuffereRedader类中的方法
而键盘录入的read方法是字节in流InputStream的方法
那么能不嫩白将字节流转成字符留在使用字符流缓冲区的readLine方法呢?
//获取键盘录入对象
InputStream in=System.in;
//将字节流对象转成字符流对象,使用转成流。InputStreamReader
InputStreamReader isr=new InputStreamReader(in);
//为了提高效率,将字符串进行缓冲区技术高效操作。使用BufferedReader
BufferedReader br=new BufferedReader(isr);
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
String line=null;
while(line=br.readLine())!=null)
{
if("over".equals(line))
break;
System.out.println(line.toUpperCase);
}
bufr.close();
OutputStreamWriter
字符流通向字节流的桥梁
OutputStream os=System.out;
OutputStreamWeader osw=new OutputStreamWeader(os);
BufferedWriter bufw=new BufferedWriter(osw)
BufferedWriter bufw=new BufferedWriter(new OutputStreamWirter(System.out))
String line=null;
while((line=bufr.readLine())!=null){
if("over".equals(line))
break;
osw.write(line.toUpperCase();
bufw.newLine();
osw.flush();
}
bufr.close();
newLine方法是字符流BuffereWriter类中的方法
BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream("txt"))); 键盘文件
BufferedWriter bufw=new BufferedWriter(new OutputStreamWirter(new FileOutputStream("txt"))) 文件控制台
流操作基本规律:
通过两个明确来完成。
1.明确源和目的
源:输入流 InputStream Reader
目的:输出流 OutputStream Writer
2.操作的数据是否是纯文本
是:字符流
不是:字节流
3.当体系明确后,在明确要使用哪个具体的对象.
通过设备来进行区分:
原设备:内存,硬盘,键盘
目的设备:内存,硬盘,控制台
例子分析:
1.将一个文本文件中数据存储到另一个文件中.复制文件
源:因为是源,所以使用读取流.inputStream Reader
是不是操作文本文件。
是,这时就可以选择Reader
这样体系就明确了。
接下俩明确要使用该体系中的哪个对象。
明确设备:硬盘。上一个文件。
Reader体系中可以操作文件的对象是FileReader
是否要提高效率:是!加入Reader体系中缓冲区 BufferedReader
目的:OutputStream Writer
是不是操作文本文件。
是,这时就可以选择Writer
明确设备:硬盘。上一个文件。
Writer体系中可以操作文件的对象是FileWriter
是否要提高效率:是!加入Writer体系中缓冲区 BufferedWriter
2.需求:将键盘录入的数据保存到一个文件中。
这个需求中有源和目的都存在
源:InputStream Reader
是不是纯文件?是!Reader
设备:键盘。对应的对象是System.in
不是选择Reader吗?System.in对应的不是字节流吗
为了操作键盘的文本数据方便。转成字符流按照字符串操作时最方便的
既然明确了Reader,那么就将System.in转换成字符流
用了Reader体系中转换流,InputStreamReader
InputStreamReader isr=new InputStreamReader(System.in)
需要提高效率吗?需要BufferedReader
BufferedReader bufr=new BufferedReader(isr)
目的:OutputStream Writer
是不是纯文件?是!Writer
设备:硬盘。一个文件。使用FileWriter
FileWriter fw=new FileWriter("txt")
需要提高效率吗?需要BufferedWriter
BufferedWriter bw=new BufferedWriter(fw);
***********
扩展一下,要把录入的数据按照指定的编码表(utf-8),将数据存到文件中。
目的:OutputStream Writer
是不是纯文件?是!Writer
设备:硬盘。一个文件。使用FileWriter
但是存储时,需要加入指定编码表。而指定的编码表只有转换流可以指定。
所以要使用的对象是OutputStream
而该转换流对象要字节输出流。而还可以操作的文件的字节流输出流。FileOutputStream
FileOutputStream fw=new FileOutputStream("txt")
OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("txt"),"UTF-8")
需要提高效率吗?需要BufferedWriter
BufferedWriter bw=new BufferedWriter(fw);
记住:转换流是什么时候使用,字符和字节之间的桥梁,通常,涉及到字符编码转换时,需要用到转换流
***********
System.setIn(new FileInputStream("person.java")) //고정 指定源
System.setOut(new PrintStream("zz.txt ")) //指定目的
catch(Exception e){
e.printStackTrace(new PrintStream("a.txt"))
}
-------
Properties prop=System.getProperties();
prop.list(new PrintStream("sysinfo.txt"))
File类
用来将文件或者文件夹封装成对象
方便对文件与文件夹的属性信息进行操作
File对象可以作为参数传递给流的构造函数
(1)第一种:将a.txt封装成file对象。可以将已有的和为出现的文件或者文件夹封装成对象。
File f1=new File("a.txt");
(2)第二种:
File f2=new File("c:\\abc","b.txt")
separator 目录分隔符
new File("c:"+File.separator+"abc"); //能跨平台
File类常见方法:
1.创建
boolean createNewFile():在指定位置创建文件,如果该文件已经存在,则不创建,返回flase
和输出流不一样,输出流对象已建立创建文件。而且文件已经存在,会覆盖。
boolean mkdir() //创建一级目录
boolean mkdirs() //创建多级文件夹
2.删除
Boolean delete() //删除失败返回false
void deleteOnExit() //退出时删除
3.判断
boolean canExcute() //能不能执行
compareTo(File pathname)
boolean exists() //文件是否存在
boolean isDirectory() //是否是目录
Boolean isFile() //是否是文件
Boolean isHidden() //是否隐藏文件
Boolean isAbsolute() //是否绝对路径
记住:在判断文件对象是否是文件或者目的时,必须要先 判断该文件对象封装的通过exists判断
4.获取信息
getName();
getPath();
getParent(); //该方法返回的是绝对路径中的父目录,否者相对路径返回空 getPath()里有指定目录影响
file getAbsolutFile(); //绝对路径 封装成对象
String getAbsolutePath();
long lastModified(); //最后修改的时间
long length() //文件大小
String list() //目录下所有文件目录
5.修改
File f1=new File("c:\\Test.java");
File f2=new File("c:\\hahah.java");
sop("rename:"+f1.renameTo(f2))
FilenameFilter 过滤
File dir=new Fiel(c:\\);
String[] arr=dir.list(new FilenameFilter){
Public boolean accept(File dir,String name){
return name.endsWith(".bmp");
}
}
Stirng[] list() //获取名字
File[] listFiles() //获取对象
列出指定目录下文件或者文件夹,包含子目录中的内容。
也就是列出指定目录下所有内容。
因为目录中还有目录,只要使用同一个列出目录功能的函数完成即可。
在列出过程中出现的还是目录的话,还可以再次调用本功能。
也就是函数自身调用自身。
这种表现形式,或者变成手法,成为递归。
递归要注意:
1.限定条件
2.要注意递归的次数,尽量避免内存溢出
public static void showDir(File dir){
System.out.println(dir);
File[] files=dir.listFiles();
for(int x=0;x<file.length;x++){
if(files[x].isDirectory())
showDir(files[x])
else
System.out.println(files[x])
}
}
删除一个带内容的目录
删除原理:
在window中,删除目录从里面往外删除的
Properties是hashtable的子类。
也就是所它具备map集合的特点。而且它里面存储的键值对都是字符串。
是集合中和IO技术相结合的集合容器。
该对象的特点:可以用具键值对形势的配置文件。
那么在加载数据是,需要数据有固定格式:键=值
//设置和获取元素
public static void setAndGet() //import java.util.*;
{
Properties prop=new Properties();
prop.setProperty("zhangsan","30")
set<String> names=prop.stringPropertyNames();
for(String s:names)
{
prop.getproperty(s)
}
}
//想要将Info.txt中键值数据存到集合中进行操作。
1.用一个流和Info.txt文件关联
2.杜宇一行数据,将该行数据用“=”进行切割
3.等号左边作为键,右边作为值。存入到Properties集合中即可。
BufferedReader bufr=new BufferedReader(new FileReader("info.txt"))
String line=null;
Properties prop=new Properties();
while(line=bufr.readLine()!=null)
{
String[] arr=line.split(“=”)
prop.setProperty(arr[0],arr[1]
}
bufr.close();
System.out.println(prop);
}
load(InputStream) //字节流放到集合里
list(System.out) //打印集合里保存的字节流
store(OutputStream out,String context)
Properties prot=new Properties(); //集合
FileInputStream fis=new FileInputStream("info.txt") //字节流
//将流中的数据加载进集合。
prop.load(fis); //加载
prop.list(System.out) //System.out.println(prop);
FileInputStream fis=new FileInputStream("info.txt")
store(OutputStream out.String context)
prop.store(fos,"haha")
打印刘:
该流提供了打印方法,可以将各种数据类型的数据都原样打印。
字节打印流
PrintStream
构造函数可以接受的参数类型:
1.file对象 file
2.字符串路径 String
3.字节输出流 OutputStream
字符打印流
PrintWriter
构造函数可以接受的参数类型:
1.file对象 file
2.字符串路径 String
3.字节输出流 OutputStream
4.字符输出流 Writer
SequenceInputStream` //多个流对象变成一个流对象
Vector<FileInputStream> v=new Vector<FileInputStream>();
v.add(new FileInputStream("c:\\1.txt"))
v.add(new FileInputStream("c:\\1.txt"))
v.add(new FileInputStream("c:\\1.txt"))
Enumeration<FileInputStream> en=v.elements();
SequenceInputStream sis=new SequenceInputStream(en);
FileOutputStream fos=new FileOutputStream("4.txt");
byte[] buf=new byte[1024]
int len=0;
while(len=sis.read(buf)!=-1){
fos.write(buf,0,len);
}
ObjectOutputStream (把堆里的数据序列化,而不能静态方法序列化)
Serializable
objectOutputStream oos=new ObjectOutputStream(new FileOutputStream());
oos.writeObject(new Person("lisi",39."cn"));
oos.close();
objectiInutStream oos=new ObjectInputStream(new FileOutputS tream());
Person p=(Person)oos.readObject();
oos.close();
public static final long serialVersionUID=42L;
不想某个序列化的话 加 transient int age
RandomAccessFile
wirteInt() //一次写32位整数
readInt()
seek() //调整指针
skipBytes()
该类不是算是IO体系中子类。
而是直接继承自Object
但是他是IO包中成员,因为他具备读和写功能。
内部封装了一个数组,而且通过指针对数组的元素进行操作。
可以通过getFilePointer获取指针位置。
同时可以通过seek改变指针的位置。
其实完成读写的原理就是内部封装了字节输入流和输出流。
通过够重啊函数可以看出,该类只能操作文件。
而且操作文件还有模式:只读r,读写rw
如果模式为只读r。不会创建文件。会去读取一个以存在文件,如果该文件不存在,则会出现异常。
如果模式rw。操作的文件不存在,会自动创建。如果存在则不会覆盖
RandomAccessFile raf=new RandomAccessFile("ran.txt","rw"); //有r和rw
raf.writeInt(274); //一次写32位整数
raf.write("lisi".getBytes());
RandomAccessFile raf=new RandomAccessFile("ran.txt","r");
byte[] buf=new byte[4];
raf.seek(8); //调整指针
raf.read(buf);
String name=new String(buf);
System.out.println(name);
int age=raf.readInt();
System.out.println(age);
raf.close()
DateInputStream DateOutputStream
可以用于操作基本数据类型的数据的流对象。
ByteArrayOutputStream ByteArrayInputStream //不需要抛异常
用于操作字节数组的流对象。
ByteArrayInputStream:在构造的时候,需要接受数据源,而且数据源是一个字节数组。
ByteArrayOutputStream:在构造的时候,不用定义数据目的,因为该对象中已经内部封装了可变长度的字节数组,这就是数据目的地。
因为这两个流对象都操作的数组,并没有使用系统资源,所以,不用进行close关闭。
//数据源
ByteArrayInputStream bis=new ByteArrayInputStream("abcdefd".getBytes())
//数据目的
ByteArrayOutputStream bos=new ByteArrayOutputStream();
bos.writeTo(new FileOutputStream("a.txt")); //他得要抛异常
在流操作规律讲解时:
源设备:
键盘 System.in 硬盘 FileStream 内存 ArrayStream
目的设备:
控制台 System.out 硬盘 FileStream 内存 ArrayStream
用流的读写思想来操作数组。
字符流的出现为了方便操作字符。
更重要是加入了编码转换。
通过子类转换流来完成。
inputStreamReader
OutputStreamWriter
------------
编码:字符串变成字节数组。
解码:字节数组变成字符串。 Arrays.toString()
String-->byte[]:str.getByte()
byte[]-->String: new String(byte[])