黑马程序员——IO流(其他流)
来源:互联网 发布:stage淘宝官网 编辑:程序博客网 时间:2024/06/06 18:13
-------android培训、java培训、期待与您交流! ---------
一、
ObjectInputStream 和 ObjectOutputStream
对象存储在堆内存中,当使用完了就会被当做垃圾回收,对象就不存在了
可以通过流的方式将堆内存对象存储在硬盘上,即使程序结束,
对象也不会消失,想要使用时,直接读取存储对象的文件即可
这种方式被称为对象的序列化
操作对象
ObjectInputStream与ObjectOutputStream
被操作的对象需要实现Serializable(标记接口)
ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。
可以使用 ObjectInputStream 读取(重构)对象。
构造方法:ObjectOutputStream(OutputStream out)
创建写入指定 OutputStream 的 ObjectOutputStream。
方法:writeObject(Object obj) 将指定的对象写入 ObjectOutputStream。
当要序列化的对象不能实现java.io.Serializable 接口。
方法抛出NotSerializableException
Serializable:类通过实现 java.io.Serializable 接口以启用其序列化功能。
未实现此接口的类将无法使其任何状态序列化或反序列化。
可序列化类的所有子类型本身都是可序列化的。
序列化接口没有方法或字段,仅用于标识可序列化的语义。
ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化。
//将一个对象写入到一个文件中
public static void writeObj()throws IOException
{ //所存储对象的文件一般不存成.txt,这里应该存成 Person.Object
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.txt"));
oos.writeObject(new Person("lisi",39));//调用写对象方法(已建立好的Person类)
oos.close();
}
//将写入文件的对象读出来
public static void readObj()throws Exception
{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.txt"));
//调用读对象方法,返回值类型是Object,因为对象是Person,返回值类型可以直接写Person
Person p = (Person)ois.readObject();//需要强制转换成类类型
//此方法抛出 ClassNotFoundException(类没有找到异常)
System.out.println(p);
ois.close();
}
二、
DataInputStream 和 DataOutputStream
可以用于操作基本数据类型的数据的流对象
DataOutputStream:
writeUTF(String str)
以与机器无关方式使用 UTF-8 修改版编码将一个字符串写入基础输出流。
DataInputStream:
readUTF(DataInput in)
从流 in 中读取用 UTF-8 修改版格式编码的 Unicode 字符格式的字符串;然后以 String 形式返回此字符串。
抛出:EOFException - 如果此输入流在读取所有字节之前到达末尾。
public static void writeUTFDemo()throws IOException
{
DataOutputStream dos = new DataOutputStream(new FileOutputStream("utfdata.txt"));
dos.writeUTF("你好");
dos.close();
}
public static void readUTFDemo()throws IOException
{
DataInputStream dis = new DataInputStream(new FileInputStream("utfdata.txt"));
String s = dis.readUTF();
System.out.println(s);
dis.close();
}
public static void writeData()throws IOException
{
DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));
//直接操作基本数据类型
dos.writeInt(234);
dos.writeBoolean(true);
dos.writeDouble(9887.543);
dos.close();
}
public static void readData()throws IOException
{
DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));
//读取时要按顺序读取
int i = dis.readInt();
boolean b = dis.readBoolean();
double d = dis.readDouble();
System.out.println("i="+i);
System.out.println("b="+b);
System.out.println("d="+d);
dis.close();
}
三、
PrintStream 和 PrintWriter
打印流:
该流提供了打印方法,可以将各种数据类型的数据原样打印
字节打印流:
PrintStream
构造函数可以接收的参数类型:
1,file对象。File
2,字符窜路径。String
3,字节输出流。OutputStream
字符打印流:
PrintWriter
1,file对象。File
2,字符窜路径。String
3,字节输出流。OutputStream
4,字符输出流。writer
public static void main(String[] args) throws IOException
{
BufferedReader bufr =
new BufferedReader(new InputStreamReader(System.in));
//PrintWriter out = new PrintWriter(new FileWriter("a.txt"),true); //写入到文件
PrintWriter out = new PrintWriter(System.out,true);//定义一个打印流,输出在控制台上
String line = null; //此处用true下面就不用flush刷新,只有println,printf,format刷新缓冲区
while((line=bufr.readLine())!=null)
{
if("over".equals(line))
break;
out.println(line.toUpperCase());//打印流的输出方法
out.flush();
}
out.close();
bufr.close();
}
四、
PipedInputStream 和 PipedOutputStream
管道流
PipedInputStream和PipedOutputStream
输入输出可以直接进行连接,通过结合线程使用
通常,数据由某个线程从 PipedInputStream 对象读取,
并由其他线程将其写入到相应的 PipedOutputStream。
不建议对这两个对象尝试使用单个线程,因为这样可能死锁线程。
//管道输入流线程
class Read implements Runnable
{
private PipedInputStream in;
Read(PipedInputStream in)
{
this.in = in;
}
public void run()
{
try
{
//管道流读数据
byte[] buf = new byte[1024];
int len = in.read(buf);
String s = new String(buf,0,len);
System.out.println(s);
in.close();
}
catch (IOException e)
{
throw new RuntimeException("读取失败!");
}
}
}
//管道输出流线程
class Write implements Runnable
{
private PipedOutputStream out;
Write(PipedOutputStream out)
{
this.out = out;
}
public void run()
{
try
{
//管道流写数据
out.write("piped lai la".getBytes());
out.close();
}
catch (IOException e)
{
throw new RuntimeException("写出失败!");
}
}
}
五、
ByteArrayInputStream 和 ByteArrayOutputStream
操作字节数组的流对象
ByteArrayInputStream和ByteArrayOutputStream
ByteArrayInputStream:
ByteArrayInputStream 包含一个内部缓冲区,该缓冲区包含从流中读取的字节。内部计数器跟踪 read 方法要提供的下一个字节。
关闭 ByteArrayInputStream 无效。此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException。
在构造的时候,需要接受数据源,而且数据源是一个字节数组
ByteArrayOutputStream:
此类实现了一个输出流,其中的数据被写入一个 byte 数组。缓冲区会随着数据的不断写入而自动增长。可使用 toByteArray() 和 toString() 获取数据。
关闭 ByteArrayOutputStream 无效。此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException。
在构造的时候,不用定义数据目的,因为该对象中已经内部封装了可变长度的字节数组,这就是数据的目的地
因为这两个流对象都操作的是数组,并没有使用体统资源,所以,不用进行close关闭
在流操作规律时讲解:
源设备:
键盘 System.in 硬盘 FileStream 内存 ArrayStream
目的设备:
控制台 System.out 硬盘 FileStream 内存 ArrayStream
用流的读写思想来操作数组
同理:
操作字符数组:
CharArrayReader CharArrayWriter
操作字符串:
StringReader StringWriter
public static void main(String[] args)
{
//数据源 //此处接受的是字节数组
ByteArrayInputStream bis = new ByteArrayInputStream("abcdefg".getBytes());
//数据目的
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int by = 0;
while((by=bis.read())!=-1)
{
bos.write(by);
}
System.out.println(bos.size());//打印目的数组的长度
System.out.println(bos.toString());
}
六、
SequenceInputStream
序列流:SequenceInputStream对多个流进行合并
作用:表示其他输入流的逻辑串联。它从输入流的有序集合开始,并从第一个输入流开始读取,
直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。
就是将多个流对象拼成一个流对象
需求:将三个文件复制到一个文件中
用SequenceInputStream将三个文件合并,再写入另一个文件
public static void main(String[] args) throws IOException
{
Vector<FileInputStream> v = new Vector<FileInputStream>();
//使用集合Vector将三个流对象添加进去
v.add(new FileInputStream("1.txt"));
v.add(new FileInputStream("2.txt"));
v.add(new FileInputStream("3.txt"));
Enumeration<FileInputStream> en = v.elements();
//构造函数接受Enumeration,集合中只有Vector使用Enumeration
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);
}
fos.close();
sis.close();
}
七、
字符编码
字符编码
字符流的出现为了方便操作字符
更重要的是加入了编码转换
通过子类转换流来完成
InputStreamReader
OutputStreamWriter
在两个对象进行构造的时候可以加入字符集
编码表的由来
计算机只能识别二进制数据,早期由来是电信号
为了方便应用计算机让它可以识别各个国家的文字
就将各个国家的文字用数字来表示,并一一对应,形成一张表
这就是编码表
常见的编码表
ASCII:美国标准信息交换码
用一个字节的7位可以表示
ISO8859-1:拉丁码表,欧洲码表
用一个字节的8位表示
GB2312:中国的中文编码表
GBK:中国的中文编码表升级,融合更多的中文文字符号
Unicode:国际标准码,融合了多种文字
所有文字都用两个字节来表示,java语言使用的就是Unicode
UTF-8:最多用三个字节来表示一个字符
/*
编码:字符串变成字节数组
String-->byte[]:str.getBytes(charseName);
解码:字节数组变成字符串
byte[]-->String:new String(byte[].charseName);
*/
import java.util.*;
class EncodeDemo
{
public static void main(String[] args) throws Exception
{
demo_2();
}
public static void demo_1()throws Exception
{
String s = "你好";
//编码。默认情况下是GBK
byte[] b = s.getBytes("GBK");//UnsupportedEncodingException抛出异常
System.out.println(Arrays.toString(b));//打印编码对应的数
//解码,就是将字符数组变成字符串
String s1 = new String(b,"GBK");
System.out.println("s="+s);
}
public static void demo_2()throws Exception
{
String s = "你好";
//按照GBK进行编码
byte[] b1 = s.getBytes("GBK");
System.out.println(Arrays.toString(b1));
//按照ISO8859-1解码,解码错误,会出现乱码
String s1 = new String(b1,"ISO8859-1");
System.out.println("s1="+s1);
//出现乱码就要解决:将得到的乱码再进行编码
byte[] b2 = s1.getBytes("ISO8859-1");
System.out.println(Arrays.toString(b2));
//然后再按照GBK解码,就能得到原来的数据
String s2 = new String(b2,"GBK");
System.out.println("s2="+s2);
//上诉方法对于出现乱码的解决是通用的,但当解码错误时,是按照UTF-8解的码
//就不能使用一上面的方法,因为GBK和UTF-8都识别中文,所以用上诉方法还是会出现乱码
//Tomcat服务器默认使用的是ISO8859-1编码表
}
}
/*
新建一个记事本文件,写入'联通',保存在打开以后发现出现了乱码,
这是因为解码时出现了问题,当存储的时候是按照GBK来存储的,
再次打开时,记事本软件是按照UTF-8来解码的,所以出现了乱码
那么为什么会出现这种现象呢?
UTF-8的码表从最低一个字节表示一个字符到最高三个字节表示一个字符
当它解码时怎么确定这一个字符是几个字节表示的呢?
怎么确定此时是读一个字节、两个字节还是三个字节,来返回这个字符呢?
GBK用两个字节代表一个字符,而UTF-8最高用三个字节来代表一个字符
当解码时,UTF-8有它自己的编码标志,符合这一标志,记事本就自动按照
UTF-8来解得码,那么UTF-8的编码是什么样的呢?
Utf-8的码表其实对它的字节都加了标识头信息,用此信息就能识别
解码时是读一个、两个还是三个字节
'\u0001' 到 '\u007F' 范围内的所有字符都是用单个字节表示的:
位值
字节 1 0 位 6-0
null 字符 '\u0000' 以及从 '\u0080' 到 '\u07FF' 的范围内的字符用两个字节表示:
位值
字节 1 1 1 0 位 10-6
字节 2 1 0 位 5-0
'\u0800' 到 '\uFFFF' 范围内的 char 值用三个字节表示:
位值
字节 1 1 1 1 0 位 15-12
字节 2 1 0 位 11-6
字节 3 1 0 位 5-0
想要解决这个问题很简单,只要“联通”前面还有别的文字就可以了
*/
class EncodeDemo2
{
public static void main(String[] args) throws Exception
{
String s = "联通";
byte[] by = s.getBytes("GBK");//编码
for(byte b : by)
{
//打印编码是得到的每个字节的十进制数
//System.out.println(b);
//打印结果:-63 -86 -51 -88
//用二进制打印一下,保留最低八位,&255
System.out.println(Integer.toBinaryString(b&255));
/*打印结果:11000001 打印结果显示“联通”所对应的二进制数
10101010 正好和UTF-8的编码标识头对应上了,所以
11001101 在解码的时候,记事本就按照UTF-8码表了
10101000*/
}
}
}
- 黑马程序员——IO流(其他流)
- 黑马程序员----IO流(其他)
- 黑马程序员---IO其他流
- 黑马程序员--IO其他流
- 黑马程序员——>第十八天<其他对象-io流>
- 黑马程序员java学习—IO其他流
- 黑马程序员——Java基础---io流(io中的其他对象)
- 黑马程序员——Java中IO流(字节流 字符流 其他流 )
- 黑马程序员——————IO流(二)_File类、其他流
- 黑马程序员——IO(对象序列化、管道流、其他流对象)
- 黑马程序员—其他流
- 53.黑马程序员-IO流-其他流
- 黑马程序员-IO流其他流对象
- 黑马程序员_IO3_其他的IO流
- 黑马程序员--IO流04--其他类
- 黑马程序员-day20-IO流(其他类)
- 黑马程序员15.其他对象&IO流
- 黑马程序员--IO流之其他
- Android 之AsyncTask 学习
- 选择排序
- NotePad++实现16进制显示文本的方法
- 七个对我最好的职业建议(精简版)
- HTTP上传JSON
- 黑马程序员——IO流(其他流)
- android多媒体——6步学会MediaRecorder录音
- 放空自己
- Ubuntu update appear GPG problem
- Servlet初始化、运行、销毁全部过程
- 在北京这半年呢
- hdu(2546)——饭卡(背包dp)
- Myeclipse 破解
- C++ 使用模板实现单例模式