黑马程序员_IO(非常重要)

时间:2023-02-18 08:11:24

----------- android培训java培训、java学习型技术博客、期待与您交流! ------------

IO流的特点及相关问题

l IO流用来处理设备之间的数据传输
设备:硬盘,内存,键盘录入
l Java对数据的操作是通过流的方式
l Java用于操作流的对象都在IO包中
l 流按操作数据分为两种:字节流与字符流。
l 流按流向分为:输入流,输出流。
1、输入流和输出流的流向的理解?流就是处理数据的一种方式或者一种手段,或者理解为一种数据流。
从硬盘已有的数据读取出来放内存里面的这个过程就是输入流。
外部--------->内存输入流   读
把内存中的数据存储到硬盘中的这个过程就是输出流。
内存--------->外部输出流 写
简单理解就是:以内存为中心。
2、什么时候使用流对象?操作设备上的数据或操作文件的时候可以使用。
二、字符流
字符流的抽象基类:Reader &Writer
1、字符流的理解,由来和作用?由于很多国家的文字融入进来,比如说中文在编码表中默认占2个字节。(在UTF-8中是3个字节)而为了按照文字的单位来处理,所以出现了字符流。
由来:后期编码表的不断出现,识别某一文字的码表不唯一。比如中文,GBK&unicode都可以识别,就出现了编码问题,为了处理文字数据,就需要通过早期的字节流+编码表结合完成。
作用:为了更便于操作文字数据。
结论:只要是处理纯文本数据,就要优先考虑使用字符流,除此之外都是用字节流。

------------------------------------------------------------------------------------------------------------------------------------------------------------------
IO:输入就是input,输出是output,输入和输出就是某个方向流动的数据流。
Java对数据的操作是通过流的方式。输入和输出是相对于内存而言,将外设中的数据读取到内存中就是输入 ,将内存的数据写入到外设中就是输出。
流按操作数据分为两种:字节流和字符流。
流按流向分为:输入流和输出流。

字符流的由来:
其实就是:字节流读取指定文字字节数据后,不直接操作,而是先查指定的编码表。获取对应的文字。
再对文字进行操作。简单说:字节流+编码表。

字节流的抽象基类:
InputStream,OutPutStre+am。
字符流的抽象基类:
Reader,Writer。
由这四个类派生出来的子类名称都是以父类名作为后缀。
而且子类的前缀名就是该对象的功能。
例:InputStream的子类FileInputStream
Reder的子类FileReader

如果要操作文字数据,优先考虑字符流。
为了提高效率加入了缓冲区,缓冲区的设计使用了装饰设计模式。
字符流缓冲区:
BufferdeWriter:
newLine();
BufferddReader:
readLine()---以null作为结束标记
缓冲区的实现原理:
自定义的读取缓冲区。其实就是模拟一个BufferedReader。
分析:缓冲区中就是封装了一个数组,
并对外提供了更多的方法对数组进行访问。
其实这些方法最终操作的都是数组的指针。
缓冲的原理:
其实就是从源中获取一起数据装进缓冲区中。
再从缓冲区中不断的取出一个一个数据。
在此次取完后,在从源中继续取一批数据放进缓冲区。
当源中的数据取光时,用-1作为结束标记。
-----------------------------------------------------------------

import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;


/**
* 自定义的读取缓冲区。其实就是模拟一个BufferedReader。
*
* 分析:缓冲区中就是封装了一个数组, 并对外提供了更多的方法对数组进行访问。 其实这些方法最终操作的都是数组的指针。
*
* 缓冲的原理: 其实就是从源中获取一起数据装进缓冲区中。 再从缓冲区中不断的取出一个一个数据。
*
* 在此次取完后,在从源中继续取一批数据放进缓冲区。
*
* 当源中的数据取光时,用-1作为结束标记。
*
* @author 张熙韬
*
*/
public class MyBufferedReader {


FileReader fr;


public MyBufferedReader(FileReader fr) {
this.fr = fr;
}


public String MyReadLine() throws IOException {


int ch = 0;
StringBuffer sb = new StringBuffer();
while ((ch = fr.read()) != -1) {
if (ch == '\r') {
continue;
}
if (ch == '\n') {
return new String(sb);
} else {
sb.append((char) ch);
}


}
if (sb.length() != 0) {
return sb.toString();
}
return null;
}


public void close() throws IOException {
fr.close();
}
}



-----------------------------------------------------------------
StringBuilder和StringBuffer的区别
Java升级三种情况:
1.提高效率
2.提高安全性
3.简化书写
String(字符串):
特性:一旦被初始化,就不能被改变
StringBuilder(线程不同步) 升级的结果(提高效率)
   将StringBuilder实例用于多线程是不安全的。如需要这样的同步,建议使用StringBuffer;
   单线程使用StringBuilder效率高;
StringBuffer(线程同步,安全的)
    StringBuffer是字符串缓冲区
    是一个容器(数据类型不确定,数据个数不确定,用StringBuffer比数组方便)
    特点:
    1.长度是可以变化的
    2.可以直接操作多个数据类型(append 添加什么类型都可以)
    3.最终会通过toString方法变成字符串
1.存储:
       StringBuffer append():将制定数据作为参数添加到已有数据的结尾处
       StringBuffer insert(index,数据):可以将数据插入制定在index位置
    2.删除
       StringBuffer delete(strat,end):删除缓冲区的数据,包含start,不包含end
       StringBuffer deleteCharAt(index):删除指定位置的字符
    3.获取
       char charAt()
        int indexOf(String str)
        int lastIndexOf(String str)
        int length()
        String subString(int start,int end)
    4.修改
       StringBuffer replace(start,end,string)
       void setCharAt(int index,char ch);
    5.反转
       StringBuffer reverse();
    6.将缓冲区中指定数据,存储到指定字符数组中
       void getChars(int srcBegin(字符串的起始位置),int srcEnd(字符串的结束位置),char[] dst,int dstBegin(字符数组的起始位置))
JDK1.5版本之后出现了StringBuilder
    StringBuffer 是线程同步
    StringBuilder是线程不同步(效率高)
    以后开发建议使用StringBuilder


 下面是一小段代码来体现上面的方法:
class StringBufferDemo 


{
public static void main(String[] args)
{
StringBuffer sb = new StringBuffer();
StringBuffer sb1 = sb.append("abc").append(34).append("def");
//方法调用链 返回值为StringBuffer对象
sop(sb.toString());//返回结果为abc34def
sop(sb1.toString());//返回结果为abc34def
//sb.delete(1,3); sop(sb.toString());
//清空缓冲区 sb.delete(0,sb.length());
//删除单个元素 sb.deleteCharAt(2);
//sb.replace(1,3,"hello");//替换
//sb.setCharAt(2,'s');
//sop(sb.toString());
char[] ch = new char[6];
sb.getChars(0,4,ch,1);
for(int x=0;x<ch.length;x++)
{
sop("ch["+x+"]=:"+ch[x]);
}
}
public static void sop(String str)
{
System.out.println(str);
}
}


--------------------------------------------------------------------
流操作的基本规律:
最痛苦的就是,流对象有很多,不知道用哪一个!
想要知道开发时用到哪些对象,通过四个明确即可确定。
明确一:明确目的和源
源:InputStream、Reader
目的:OutputStream、Writer


明确二:明确数据是否是纯文本
源:是纯文本:字符流 Reader。不是:字节流 InputStream
目的:是纯文本Writer。不是:OutputStream


明确三:明确具体的设备
源设备:
硬盘:File
键盘:System.in (Ctrl+C结束)
内存:数组
网络:Socket流


目的设备:
硬盘:File
键盘:System.out
内存:数组
网络:Socket流


例子:将一个文本文件中的数据存储到另一个文件中。复制文件
源:因为是源,所以使用读取流。InputStream ,Reader
是不是操作文本文件。
是!可以选择Reader
接下来明确要使用该体系中的哪个对象
明确设备:硬盘
Reader体系中可以操作文件的对象时FileReader




明确四:是否需要其他功能。
是否需要高效:是,加上Buffer 使用缓冲区就必须flush
是否需要对象序列化:ObjectInputStream
是否需要操作基本数据类型:DateInputStream,DateOutputStream


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


小插曲:设置源:System.setIn(new FileInputStream("love.txt"));


设置目的:System.setOut(new PrintStream("111.txt"));
前提是必须使用System.in 和System.out作为标准输出输入
-----------------------------------------------------------------
package com.zxt.MyLineNumberReaderDemo;


import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;






/**
* 采用继承方式重写MyLineNumberReaderDemo1类
* @author 张熙韬
*
*/
public class MyLineNumberReaderDemo1 extends BufferedReader{
public MyLineNumberReaderDemo1(Reader in) {
super(in);
}


private int linenumber;


public String readLine() throws IOException{
linenumber++;
return super.readLine();
}

public int getLineNumber(){
return linenumber;
}

public void setLineNummber(int linenumber){
this.linenumber=linenumber;
}

}
/*public class MyLineNumberReaderDemo1 {
private Reader reader;
private int linenumber;

public MyLineNumberReaderDemo1(Reader reader){
this.reader=reader;
}

public String readLine() throws IOException{
linenumber++;
StringBuffer sb=new StringBuffer();
int ch=0;
while((ch=reader.read())!=-1){
if(ch=='\r'){
continue;
}
if(ch=='\n'){
return new String(sb);
}
sb.append((char)(ch));
}

if(sb.length()!=0){
return new String(sb);
}
return null;
}

public int getLineNumber(){
return linenumber;
}

public void setLineNummber(int linenumber){
this.linenumber=linenumber;
}

public void close() throws IOException{
reader.close();
}
}*/


-----------------------------------------------------------------
装饰设计模式。
解决问题:给已有的对象提供增强额外的功能。还不用对原有对象进行修改。


比继承更为灵活。


Writer
|--TestWriter
|--MediaWriter


现有一个体系用于各种数据的写入。


但是,防线写入效率有点低。想要对其进行效率的提高。
可以使用缓冲技术来完成的。


以后对象的写入方法,不够高效,可以通过派生子类的形式对齐进行复写,定义高效的写入动作。
Writer
|--TestWriter
|--BufferTextWriter
|--MediaWriter
|--BufferMediaWriter
通过继承的方式提高了效率。
但是对于扩展性是一个问题。而且所需的功能越多,子类就越多。
一旦加入新类,就需要为它提供高效。麻烦!


如何解决这个问题呢?优化!
既然都需要缓冲,对数据写入的效率进行提高。
可以转变一下思想,这样来做,将缓冲技术单独进行封装。
哪个对象需要缓冲,就把哪个对象传递给缓冲对象即可。


Class Buffer{


Buffer(TestWriter w){
}
Buffer(MediaWriter w){
}
}
为了便于扩展,可以对一组对象进行缓冲。
Class BufferWriter extends Writer{
Buffer(Writer w){
}
Public void write(){
}
}
体系就变成了这样:
Writer
|--TextWriter
|--MediaWriter
|--BufferWriter
BufferWriter的出现,增强了Writer体系中的功能。
这种设计方式比原来更为灵活,避免了继承的臃肿。
将这样解决方式就定义了一个名称方便于后人使用:装饰设计模式。


-------------------------------------------------------------------
转换流:
InputStreamReader:字节流通向字符流的桥梁。
OutputStreamWriter:字符转成字节的桥梁。


转换流在字符流的体系当中,这也是为什么构造函数为
InputStreamReader isr=new InputStreamReader(in);
BufferedReader bufr=new BufferedReader(isr);
-----------------------------------------------------------------
复制文本文件的原理首先用一个读取流对象和一个文件进行关联,然后用一个写入流对象作为目地的,为了把读取流中的文件传输到目的地流对象中,我们就提供了一个字符数组,为了关联这个数组,所以读取流对象有一个read()方法与这个字符数组进行关联,同理,写入流对象也有一个write()方法与这个字符数组进行关联,这样2个流对象就相连接了,而这个字符数组就相当于一个中转站




将e盘的文件复制到f盘中
public class CopyFileTest {
public static void main(String[] args) {
File startfile = new File("e:\\a.txt");
File endfile = new File("f:\\hello.txt");
copyFile(startfile, endfile);
}


public static void copyFile(File startfile, File endfile) {
FileReader fr = null;
FileWriter fw = null;
try {
// 1,创建一个字符读取流读取与源数据相关联。
fr = new FileReader(startfile);
// 2,创建一个存储数据的目的地。
fw = new FileWriter(endfile);
// 3,创建一个字符数组将读取流对象和写入流对象相连接。
char[] buf = new char[1024];
// 4,每次读取的长度不一样,所以定义一个变量.
int len = 0;
// 5,用循环读取文件中的数据
while ((len = fr.read(buf)) != -1) {// 判断是否读取完没
fw.write(buf, 0, len);// 为了只写入有效的数据
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fr != null) {
try {
fr.close();
} catch (Exception e2) {
throw new RuntimeException("读取流关闭失败");
}
}
if (fw != null) {
try {
fw.close();
} catch (Exception e2) {
throw new RuntimeException("写入流关闭失败");
}
}
}
}
}


-----------------------------------------------------------------
File类:用来将文件或者文件夹封装成对象。
封装成相对路径,打印相对,封装成绝对路径,打印成绝对路径!
方便对文件或文件夹的属性进行操作。
构造函数:File.separator
File.separator跨平台的分隔符


File对象常见方法:
1.获取:
1.1获取文件名称。
String getName();
1.2获取文件路径.
StringgetPath();
StringgetAbsolutePath();
1.3获取文件大小.
long length();
1.4获取文件修改时间。(判断修改时间,来加载修改后的新文件。)
longlastModified();
2.创建和删除。
booleancreateNewFile();文件不存在就创建,文件存在不创建。
booleandelete();
deleteOnExit();在退出时删除。
File dir = new File("abc\\d\\e");//注意:File对象封装的是e文件夹。
boolean b = dir.mkdir();
boolean b = dir.mkdir();//创建多级目录
boolean b1 = dir.delete();//必须要由内向外删,目录里有内容删除不掉。
3.判断。
文件是否存在。
booleanexists();
booleanisDirectory();//应该先判断是否存在,不存在返回flase
boolean isFile();
4.重命名。
File f1 = new File("c:\\0.txt");
File f1 = new File("d:\\9.txt");
f1.renamenTo(f2);//剪切文件到d盘,并改名为9.txt。
5.获取系统根目录和容量
获取所有盘符:
File[] files = File.listRoots();
for(File file : files){
System.out.println(file);
}
getFreeSpace();
getTotalSpace();
6.获取目录内容。
File file = new File("c:\\");
String[] names = file.list();
for(String name : names){
System.out.println(name);
}
打印的是c盘当前目录下所有文件以及文件夹的名称,包括隐藏文件。
调用list方法的File对象中封装的必须是目录,否则会发生空指针异常。
如果目录存在但是没有内容会返回一个数组,但是长度为0.
7.过滤器。
File dir = new File("c:\\");
String[] names = dir.list(new FilterByJava());
for(String name: names){
System.out.println(name);
}
递归:
函数自身直接或者间接的调用到了自身。
一个功能在被重复使用个,并每次使用时参与运算的结果和上一次调用有关。
这时就可以用递归来解决问题。
注意:递归一定要明确条件,否则容易栈内存溢出。
注意递归的次数。次数太多会栈溢出。
小练习:
删除一个带内容的目录。
需要从里往外删,先进行深度遍历。
import java.io.File;


public class DeleteDirTest3 {
public static void main(String[] args) {
File dir = new File("d:\\dir");
deleteDir(dir);
}


private static void deleteDir(File dir) {
File[] files = dir.listFiles();
for (File file : files) {
if (file.isFile()) {
file.delete();
} else {
deleteDir(file);
}
}
dir.delete();
}
}

File类
IO中不仅为我们提供了上面介绍的对文件内容的操作,还提供了对文件本身属性的操作,那就是File类,它也是IO中很重要也是很常用的一个类。
常见方法:
1,创建。
boolean createNewFile():在指定位置创建文件,如果该文件已经存在,则不创建,返回 false。和输出流不一样,输出流对象一建立创建文件。而且文件已经存在,会覆盖。
boolean mkdir():创建文件夹。
boolean mkdirs():创建多级文件夹。
 
2,删除。
boolean delete():删除失败返回false。如果文件正在被使用,则删除不了返回false。
void deleteOnExit();在程序退出时删除指定文件。 
3,判断。
boolean exists() :文件是否存在.
isFile():
isDirectory();
isHidden();
isAbsolute();


4,获取信息。
 
getName():
getPath():
getParent():
getAbsolutePath() 
long lastModified() 
long length() 
 
File练习:将一个指定目录下的java文件的绝对路径,存储到一个文本文件中。
 
import java.io.*;


import java.util.*;


class javaFileList


{
public static void main(String[] args) throws IOException {
File dir = new File("E:\\学习资料\\学习视频");
List<File> list = new ArrayList<File>();
fileToList(dir, list);
File file = new File("E:\\学习资料\\学习视频\\javaFIleList.txt");
writeToFile(list, file.toString());
}


public static void fileToList(File dir, List<File> list) {
File[] files = dir.listFiles();
for (File file : files) {
if (file.isDirectory())
fileToList(file, list);// 递归
else {
if (file.getName().endsWith(".java"))
list.add(file);
}
}
}


public static void writeToFile(List<File> list, String javaListFile)
throws IOException {
BufferedWriter bufw = null;
try {
bufw = new BufferedWriter(new FileWriter(javaListFile));
for (File f : list) {
String path = f.getPath();
bufw.write(path);
bufw.newLine();
bufw.flush();
}
} catch (IOException e) {
throw e;
} finally {
try {
if (bufw != null)
bufw.close();
} catch (IOException e) {
throw e;
}
}
}
}


 
此练习中涉及到一个比较重要的算法:递归
 
递归的特点:调用自身方法。
-----------------------------------------------------------------
Map集合子类Properties和io流结合。
Map:
|--HashTable
|--Properties(没有泛型)
Properties集合特点:
1.集合中的键和值都是字符串对象。
2.集合中的数据可保存在流中,或从流中获取数据。
通常该集合用于操作以键值对形式存在的配置文件。
Properties集合和流结合使用:
store方法:(持久化)
prop.store(FileOutputStream fos, "name+age");//不能传中文信息。
Load方法:
prop.load(FileInputStream fis);
-----------------------------------------------------------------
序列流:对多个流进行合并。字节流。
构造函数接收枚举类型。
SequenceInputStream(Enumeration en)
使用方法:
将流添加进ArrayList集合,后使用Collections的静态方法。




//文件组合与分割的例子
public class SplitFile {

public static void main(String[] args) throws Exception{
//splitFile();
merge();
}





/**
* 组合文件 !--比较这个方法与SequenceDemo的区别--!
* @throws IOException
*/
public static void merge() throws Exception{
List<FileInputStream> list=new ArrayList<FileInputStream>();
//ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
for(int i=1;i<=5;i++){
list.add(new FileInputStream(i+".part"));
}

final Iterator<FileInputStream> it=list.iterator();

Enumeration<FileInputStream> e=new Enumeration<FileInputStream>() {


@Override
public boolean hasMoreElements() {
return it.hasNext();
}


@Override
public FileInputStream nextElement() {
return it.next();
}
};
/**
* 第二种方法
Vector<FileInputStream> v=new Vector<FileInputStream>();
for (int j = 1; j <=5; j++) {
v.add(new FileInputStream(j+".part"));
}

Enumeration<FileInputStream>en =v.elements();

*/
SequenceInputStream sis=new SequenceInputStream(e);

/**
* 组合的时候,对象要创建在while循环外部!
*/
FileOutputStream fos=new FileOutputStream("00.jpg");

int len=0;
byte[] buf=new byte[1024];
while((len=sis.read(buf))!=-1){
fos.write(buf, 0,len);
}

fos.close();
sis.close();
}

/**
* 切割文件
* @throws Exception
*/
public static void splitFile() throws Exception{
FileInputStream fin=new FileInputStream("xiaosage.jpg");

FileOutputStream fout=null;

byte[] buf=new byte[1024*1024];

int len=0;
int count=1;
while((len=fin.read(buf))!=-1){
/**
* 分割的时候,对象要创建在while循环内部!
*/
fout=new FileOutputStream((count++)+".part");
fout.write(buf,0,len);
fout.close();
}

fin.close();
}


}
-----------------------------------------------------------------------------------------------------------------------------
PrintStream:
1.提供了打印方法,可以对多中数据类型值进行打印。并保持数据的表现形式。
2.不抛出IOException
构造函数,接收三种类型的值:
1.字符串路径。
2.File对象。
3.字节输出流。
PrintWriter:字符打印流。
构造函数,接收四种类型的值:
1.字符串路径。
2.File对象。
3.字节输出流。
4.字符输出流。
注意:输出流能自动刷新。
PrintWriter out = new PrintWriter(new FileWriter("out.txt"),true);
-----------------------------------------------------------------
能操作对象的字节流:
ObjectInputStream:
ObjectOutputStream:
要序列化的对象要实现Serializable接口,启用序列化功能。
对象的默认序列化机制写入的内容是,对象的类,类签名,及非瞬态和非静态字段的值。
数据加transient(短暂的)修饰后不会写入,变为瞬态数据。
静态和瞬态都不会写入。
Serializable:用于给被序列化的类加入ID号。
用于判断类和对象是否是同一版本。
建议所有课序列化类都显示声明serialVersionUID值。
定义方式:
private static final long serialVersionUID = 12345L;
-----------------------------------------------------------------
管道流
public class PipedStreamDemo {
public static void main(String[] args) throws Exception{
PipedInputStream in=new PipedInputStream();
PipedOutputStream out=new PipedOutputStream();

Read read=new Read(in);
Write write=new Write(out);

//连接管道流
in.connect(out);

new Thread(read).start();
new Thread(write).start();
}
}


------------------------------------------------------------------
RandomAccessFile:
不是io体系中的子类。
特点:
1.该对象既能读又能写。
2.内部维护了一个大型 的byte可变长度数组,并通过指针可以操作数组中的元素。
3.可以通过getFilePointer方法获取指针位置,通过seek方法设置指针位置。
4.其实该对象就是将字节输入流和输出流进行了封装。
5.该对象的源或者目的只能是文件,通过构造函数就可以看出。
通常在多线程写入的时候使用


如果模式为只读 r。不会创建文件。会去读取一个已存在文件,如果该文件不存在,则会出现异常。
如果模式rw。操作的文件不存在,会自动创建。如果存则不会覆盖。
-----------------------------------------------------------------
操作基本数据类型:
DateInputStream,DateOutputStream:
readUTF()和writeUTF()方法,使用指定的utf-8修改版编码表
操作字节数组:
ByteArrayInputStream:
包含一个内部缓冲区。
ByteArrayInputStream(byte[] buf)
ByteArrayOutputStream:
实现了一个输出流,其中的数据被写入一个byte数组,缓冲区会随着数据的不断写入而自动增长。
可使用toByteArray()和toString()获取数据。关闭此流无效(对象没有调用资源,在内存中读写)。
writeTo(OutputStream out):将此byte数组输出流的全部内容写入到指定的输出流参数中,
和使用out.write(buf,o,len)调用该输出流的write方法效果一样。
ByteArrayInputStream bis = new ByteArrayInputStream("abcd".getBytes());
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int ch = 0;
while((ch=bis.read())!=-1){
bos.write(ch);
}
System.out.println(bos.toString());
操作字符数组:
CharArrayReader(源是字符数组)与CharAraryWrite
操作字符串:
SrringReader(源是字符串)与StringWriter
-------------------------------------------------------------------------
打印流:PrintWriter和PrintStream{可以直接操作输入流和文件。}
PrintStream:{打印流}
1:使它们能够方便地打印各种数据值表示形式。
2:提供了一系列的打印功能,可以打印任何数据。
3:它的特有方法不会抛出异常。
常见的一些方法:
构造方法:
该流是一个处理目的的流对象。
目的:
1:File对象。
2:字符串路径。
3:字节输出流。

格式:
PrintStream  p = new PrintStream("dd\\out.txt");

使用PrintStream继承的方法,writer。
Out.wite(886);//write将接收到整数的最后一个自己写入到流。
使用PrintStream的特有方法。Print。
Out.print(97);//print方法,可以将参数的数据表现形式打印到目录中,原理是将97转成字符串,在write到目的。
//print方法打印各种数据都会将其变成字符串,所以可以保证数据的原有数据表现形式。

PrintWriter:字符打印流。
构造函数:
1:File对象。
2:字符串路径。
3:字节输出流。
4:字符输出流。


一般不用PrintWriter定义指定的编码表,为啥呢?
因为有操作编码表专用的对象。那就是转换流。
而且转换流不仅可以写的编码表,还可以读的编码表。


序列流:SequercelnputStream{对多个流合并}
SequercelnputStream:序列流:
字面理解:将流按照有序的  

ObjectInputStream和ObjectOutputStream
1:可以用流直接操作对象。

使用ObjectOutputStream
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("路径名和文件名"))

Serializable :接口
用于给序列化的类添加一个序列版本号。
为了判断序列化的对象和对应的class类是否匹配。
版本号咋算出来的。
通过类的中的成员的数字签名算出来的。

注意:
类中的静态数据不会被序列化的。
那么非静态数据有些不需要序列化的怎么办呢?这需要一个关键字来完成,transient瞬间的,暂时的。



操作对象:ObjectlnputStream与
RandomAccessFile:
1.不是字节流体或者字符流系中的成员。
2.该类是用于操作File的类。
3.该对象既可以读取又可以写入。
4.该对象中封装一个byte类型的数组。
5.其实它内部就是封装了字节输入流和字节输出流。
6.通过seek方法设置数组的指针就可以实现对文件数据的随机读取。
可以实现数据的修改。
注意:被操作的数据一定要规律。

用于操作基本数据类型值的对象。
operateData()
ByteArrayInputStream和ByteArrayOutputStream
1.用于操作字节数组的流对象,其实它们就是对应设备为内存事物流对象。
2.该流的关闭是无效的,因为没有调用过系统资源。
3.按照流的读写思想操作数组中的元素。

编码:字符串----->字节数组
解码:字节数组----->字符串

你好:的gbk编码表:-60  -29  -70  -61
你好:的utf-8编码:-28  -67  -96  -27  -91  -67

编码:
String  str = "你好";
Byte[] buf = str.getBytes();默认码表。

解码:
String  s1 = new String(buf);默认码表。


----------- android培训java培训、java学习型技术博客、期待与您交流! ------------