黑马程序员__IO流
来源:互联网 发布:v百科网络流行语 编辑:程序博客网 时间:2024/04/29 22:50
--------- android培训、java培训、期待与您交流! ------------
IO(Input Output)流
IO流用来处理设备之间的数据传输
Java对数据的操作是通过流的方式
Java用于操作流的对象都在IO包中
流按操作数据分为两种:字节流与字符流
流按流向分为:输入流,输出流
IO流常用基类
字节流的抽象基类InputStream,OutputStream
字符流的抽象基类Reader,Writer
注:由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀
FileWriter fw = new FileWriter("demo.txt",true);
//传递一个true参数,代表不覆盖已有的文件,并在已有文件的末尾处进行数据续写
将C盘一个文本文件复制到D盘
复制的原理:其实就是将C盘下的文件数据存储到D盘的一个文件中
步骤:
1.在D盘创建一个文件,用于存储C盘文件中的数据
2.定义读取流和C盘文件关联
3.通过不断的读写完成数据存储
4.关闭资源
public static void cpoy()throws IOException
{
FileWriter fw = new FileWriter("xxx_copy.txt");//创建目的地
FileReader fr = new FileReader("xxx.txt");//与已有文件关联
char[] chs = new char[1024];
int num = 0;
while((num=fr.read(chs))!=-1)
{
fw.write(new String(chs,0,num));
}
fw.close();
fr.close();
}
BufferedWriter缓冲区的出现是为了提高流的操作效率而出现的,所以在创建缓冲区之前,必须要先有流对象
该缓冲区中提供了一个跨平台的换行符newLine()
其实关闭缓冲区,就是在关闭缓冲区中的流对象
readLine()方法返回的时候只返回回车符之前的数据内容,并不返回回车符
装饰设计模式:
当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入,基于已有的功能,并提供加强功能,那么自定义的该类称为装饰类
装饰类通常会通过构造方法接收被装饰的对象,并基于被装饰的对象的功能提供更强的功能
装饰模式比继承要灵活,避免了继承体系臃肿,而且降低了类与类之间的关系
装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强的功能,所以装饰类和被装饰类通常是都属于一个体系中的
FileOutputStream的write方法在不指定缓冲区时不用刷新字节流直接写进目的,但要close
int num = fis.available();//读取了多少个字节
键盘录入的常见写法
BufferedReader bufr =
new BufferedReader(new InputStreamReader(System.in));
流操作的基本规律:通过三个明确来完成
1. 明确源和目的
源:输入流InputStream Reader
目的:输出流OutputStream Writer
2. 操作的数据是否是纯文本
是:字符流
不是:字节流
3. 当体系明确后,再明确要使用哪个具体的对象
通过设备来进行区分:
源设备:内存,硬盘,键盘
目的设备:内存,硬盘,控制台
在存储时,需要加入指定编码表utf-8,而指定的编码表只有转换流可以指定,所以要使用的对象是OutputStrWriter而该转换流对象要接收一个字节输出流,而且还可以操作文件的字节输出流FileOutputStream
OutputStreamWriter osw =
new OutputStreamWriter(new FileOutputStream("d.txt"),"UTF-8");
所以,记住,转换流什么时候使用,字符和字节之间的桥梁,通常,涉及到字符编码转换时,需要用到转换流
System.setIn(new FileInputStream(“xxx.java”);//改变输入源
System.setOut(new PrintStream(“zz.txt”));//改变输出目的
获取系统信息到文件中(带换行的)
Properties prop = System.getProperties();
prop.list(new PrintStream("C:\\pro.txt"));
File类
用来将文件或者文件夹封装成对象,方便对文件与文件夹的属性信息进行操作,File对象可以作为参数传递给流的构造函数
separator与系统有关的默认名称分隔符
//将a.txt封装成file对象,可以将已有的和未出现的文件或者文件夹封装成对象
File f1 = new File("a.txt");
File f2 = new File("c:\\abc","b.txt");//前面是目录,后面是文件名
File d = new File("c:\\abc");
File f3 = new File(d,"c.txt");//和f2是一样的
File f = new File("file.txt");
File类常见方法
1.创建
boolean createNewFile():在指定位置创建文件,如果该文件已经存在
则不创建,返回false,和输出流不一样,输出流对象一建立创建文件,
而且文件如果已经存在,会覆盖
boolean mkdir():创建文件夹
boolean mkdirs():创建多级文件夹
2.删除
boolean delete();删除失败返回false如果文件正在被使用,则删除不了返回false
void deleteOnExit();在程序退出时删除指定文件
3.判断
boolean canExecute();判断文件是否可执行,像xxx.txt如果存在,结果为true
boolean exists():文件是否存在
isFile()
isDirectory()
isHidden()
isAbsolute()是否是绝对
4.获取信息
getName()
getPath()
getParent()
getAbsolutePath()
long lastModified()
long length()文件大小
f1.renameTo(f2);将f1对象重命名为f2对象和剪切相似
记住:在判断文件对象是否是文件或者目录时,必须要先判断文件封装的对象是否存在
通过exists判断
File f = new File("c:\\myclass");
String[] names = f.list();
//调用list方法的file对象必须是封装了一个目录,该目录还必须存在
File[] files = File.listRoots();
//获取所有盘符
//用匿名内部类过虑文件
File[] files = dir.listFiles(new FilenameFilter()
{
public boolean accept(File dir,String name)
{
return name.endsWith(".jpg");
}
});
递归要注意:
1. 限定条件
2. 要注意递归的次数,尽量避免内在溢出
删除一个带内容的目录:
删除原理:在Windows中,删除目录从里面往外删除的,既然是从里往外删除,就需要用到递归
import java.io.*;
class RemoveDir
{
public static void main(String[] args)
{
removeDir(new File("d:\\testdir"));
}
//删除文件
public static void removeDir(File dir)
{
File[] files = dir.listFiles();
for(int x = 0;x<files.length;x++)
{
if(files[x].isDirectory())
removeDir(files[x]);
else
System.out.println(files[x].toString()+ ".."+files[x].delete());
}
System.out.println(dir.toString() + ".目录." + dir.delete());
}
}
Properties是hashtable的子类,也就是说它具备map集合的特点,而且它里面存储的键值对都是字符串,是集合和IO技术相结合的集合容器
该对象的特点:可以用于键值对形式的配置文件,那么在加载数据时,需要数据有固定格式:
键=值
Properties prop = new Properties();
prop.setProperty("zhangsan","30");//设置键值对
prop.setProperty("lisi","39");
// System.out.println(prop);
String value = prop.getProperty("lisi");//根据键获取值
// System.out.println(value);
prop.setProperty("lisi","29");//修改键的值
Set<String> names = prop.stringPropertyNames();//stringPropertyNames()返回类型为Set
for(String s : names){
System.out.println(s+"..."+prop.getProperty(s));
}
打印流:
该流提供了打印方法,可以将各种数据类型的数据都原样打印
字节打印流:PrintStream
构造可以接收的参数类型
1.file对象。File
2.字符串路径。String
3.字节输出流。OutputStream
字符打印流:PrintWriter
构造可以接收的参数类型
1.file对象。File
2.字符串路径。String
3.字节输出流。OutputStream
4.字符输出流。Writer
PrintWriter out = new PrintWriter(new FileWriter("a.txt"),true);
AutoFlush只是对流而言
合并流:
import java.io.*;
import java.util.*;
class SequenceDemo
{
public static void main(String[] args) throws Exception
{
Vector<FileInputStream> v = new Vector<FileInputStream>();
v.add(new FileInputStream("c:\\1.txt"));
v.add(new FileInputStream("C:\\2.txt"));
v.add(new FileInputStream("c:\\3.txt"));
Enumeration<FileInputStream> en = v.elements();
FileOutputStream fos = new FileOutputStream("c:\\4.txt");
SequenceInputStream sis = new SequenceInputStream(en);
//合并流
int num = 0;
byte[] buf = new byte[1024];
while((num=sis.read(buf))!=-1)
{
fos.write(buf,0,num);
}
fos.close();
fis.close();
}
}
切割与合并文件
import java.util.*;
import java.io.*;
class SplitFile
{
public static void main(String[] args) throws Exception
{
splitFile();
merge();
}
public static void merge()throws Exception
{
ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
for(int i=1;i<=6;i++)
{
al.add(new FileInputStream("c:\\myclass\\"+i+".part"));
}
final Iterator<FileInputStream> it = al.iterator();
Enumeration<FileInputStream> en = new Enumeration<FileInputStream>()
{
public boolean hasMoreElements()
{
return it.hasNext();
}
public FileInputStream nextElement()
{
return it.next();
}
};
SequenceInputStream sis = new SequenceInputStream(en);
FileOutputStream fos = new FileOutputStream("c:\\myclass\\m.mp3");
byte[] buf = new byte[1024];
int len = 0;
while((len=sis.read(buf))!=-1)
{
fos.write(buf,0,len);
}
fos.close();
sis.close();
}
public static void splitFile()throws Exception
{
FileInputStream fis = new FileInputStream("c:\\m2m.mp3");
byte[]buf = new byte[1024*1024];
int len = 0;
int count = 1;
while((len = fis.read(buf))!=-1)
{
FileOutputStream fos =
new FileOutputStream("c:\\myclass\\"+(count++)+".part");
fos.write(buf,0,len);
fos.close();
}
fis.close();
}
}
对象的序列化:目的:将一个具体的对象进行持久化,写入到硬盘上。
注意:静态数据不能被序列化,因为静态数据不在堆内存中,是存储在静态方法区中。
如何将非静态的数据不进行序列化?用transient关键字修饰此变量即可。
Serializable:用于启动对象的序列化功能,可以强制让指定类具备序列化功能,该接口中没有成员,这是一个标记接口。这个标记接口用于给序列化类提供UID。这个uid是依据类中的成员的数字签名进行运行获取的。如果不需要自动获取一个uid,可以在类中,手动指定一个名称为serialVersionUID id号。依据编译器的不同,或者对信息的高度敏感性。最好每一个序列化的类都进行手动显示的UID的指定。
import java.io.*;
class ObjectStreamDemo {
public static void main(String[] args) throws Exception{
writeObj();
readObj();
}
public static void readObj()throws Exception{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.txt"));
Object obj = ois.readObject();//读取一个对象。
System.out.println(obj.toString());
}
public static void writeObj()throws IOException{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.txt"));
oos.writeObject(new Person("lisi",25)); //写入一个对象。
oos.close();
}
}
class Person implements Serializable{
private static final long serialVersionUID = 42L;
private transient String name;//用transient修饰后name将不会进行序列化
public int age;
Person(String name,int age){
this.name = name;
this.age = age;
}
public String toString(){
return name+"::"+age;
}
}
管道输入流应该连接到管道输出流;管道输入流提供要写入管道输出流的所有数据字节。通常,数据由某个线程从PipedInputStream
对象读取,并由其他线程将其写入到相应的PipedOutputStream
。不建议对这两个对象尝试使用单个线程,因为这样可能死锁线程。
管道流有两种创建方式:
1. 通过构造函数连接输入输出流PipedInputStream
(
PipedOutputStream
src)
创建PipedInputStream
,使其连接到管道输出流src
。
2. 创建无参对象 PipedInputStream
()
通过
connect
(
PipedOutputStream
src)
使此管道输入流连接到管道输出流src
。
RandomAccessFile该类不是IO体系中子类,而是直接继承自Object
但是它是IO包中成员,因为它具备读和写功能,内部封装了一个数组,而且通过指针对数组的元素进行操作,可以通过getFilePointer获取指针位置,同时可以通过seek改变指针的位置,其实完成读写的原理就是内部封装了字节输入流和输出流
通过构造函数可以看出,该类只能操作文件,而且操作文件还有模式,只读r读写rw等
如果模式为只读r不会创建文件,会去读取一个已存在文件,如果该文件不存在,则会出现异常
如果模式为rw,操作的文件不存在,会自动创建,如果存在则不会覆盖
用RandomAccessFile数据要分段,而且要有规律
DataInputStream与DataOutputStream可以用于操作基本数据类型的数据的流对象
注意:怎么写入的数据,就要按相应的顺序读取
操作字节数据
ByteArrayInputStream,在构造的时候,需要接收数据源,而且数据源是一个字节数组
ByteArrayOutputStream在构造的时候,不用定义数据目的,因为该对象中已经内部封装了可变长度的字节数组,这就是数据目的地
因为这两个流对象都操作的是数组,并没有使用系统资源,所以不用进行close关闭
关闭ByteArrayInputStream和ByteArrayOutputStream无效。它们中的方法在关闭此流后仍可被调用,而不会产生任何 IOException。只有一个方法writeTo(OutputStream out)会产生IOException
源设备
键盘System.in 硬盘FileStream 内存ArrayStream
目的设备
控制台System.out 硬盘FileStream 内存ArrayStream
操作字符数组
CharArrayReader和CharArrayWriter
操作字符串
StringReader和StringWriter
转换流的字符编码
public static void readText()throws IOException
{
InputStreamReader isr = new InputStreamReader(new FileInputStream("gbk.txt"),"GBK");
char[] buf = new char[10];
int len = isr.read(buf);
String str = new String(buf,0,len);
System.out.println(str);
}
public static void writeText()throws IOException
{
OutputStreamWriter osw =
new OutputStreamWriter(new FileOutputStream("gbk.txt"),"GBK");
osw.write("你好");
osw.close();
}
编码:字符串变成字节数组
解码:字节数组变成字符串
String-->byte[]:str.getBytes(charsetName);
byte[] -->String:new String(byte[],charsetName)
import java.util.*;
class EncodeDemo
{
public static void main(String[] args) throws Exception
{
String s = "你好";
byte[] b1 = s.getBytes("utf-8");
System.out.println(Arrays.toString(b1));
String str = new String(b1,"UTF-8");
System.out.println("str="+str);
}
}
如果解错了怎么办?
编码用码表1编成byte1,解码用码表2解成str1
再返回去就行了将str1用码表2编码编成byte2,再用码表1解码
但如果是GBK编码,却用UTF-8解码,再用这种方式就不行了,因为它们都识别中文
--------- android培训、java培训、期待与您交流! ------------
- 黑马程序员__IO流
- 黑马程序员__IO流
- 黑马程序员__IO流
- 黑马程序员__IO流
- 黑马程序员__IO流
- 黑马程序员__IO(字节流)
- 黑马程序员__IO流小结
- 黑马程序员__IO流笔记一
- 黑马程序员__IO流笔记二
- 黑马程序员__JAVA基础__IO流(一)
- 黑马程序员__JAVA基础__IO流(二)
- 黑马程序员__JAVA基础__IO流(三)
- 黑马程序员__JAVA基础__IO流(四)
- 黑马程序员__IO(字符流)
- 黑马程序员__IO流(01)
- 黑马程序员__IO流(02)
- 黑马程序员__Day03_java基础__IO流
- 黑马程序员__IO
- Linux 汇编语言开发指南
- [leetcode] first missing positive
- 新手看招 Unix和Linux下C语言学习指南
- hibernate缓存机制
- 学习python之路---python小算法总结(七)
- 黑马程序员__IO流
- AndroidManifest中original-package标签
- 读取手机通讯录
- Tomcat 发布多个web项目(多个域名,同一ip)
- GPS和A-GSP工作原理 两者并用其乐无穷
- java获取mac地址
- 如何编译Linux内核
- 多线程通信
- 什么是嵌入式工程师,发展前景如何