9159金沙游艺场


Windows 快捷方式(*.link)打开方式关联错误
图片 4
网络七层模型

Java字符集

图片 1编码与解码.png

一、对象序列化

ObjectOutputStram和ObjectInputStream

1、JVM中单个字符占用的字节长度跟编码方式有关,而默认编码方式又跟平台是一一对应的或说平台决定了默认字符编码方式;

码表:

1、概述:

将堆内存中的对象存入硬盘,保留对象中的数据,称之为对象的持久化(或序列化)

2、对于单个字符:ISO-8859-1单字节编码,GBK双字节编码,UTF-8三字节编码因此中文平台(中文平台默认字符集编码GBK)下一个中文字符占2个字节,而英文平台(英文平台默认字符集编码Cp1252(类似于ISO-8859-1))。

码表 解释
ASCII 美国标准信息交换码。用一个字节的7位可以表示。 -128~127 256
ISO8859-1 拉丁码表。欧洲码表,用一个字节的8位表示。又称Latin-1或“西欧语言”。ASCII码是包含的仅仅是英文字母,并且没有完全占满256个编码位置,所以它以ASCII为基础,在空置的0xA0-0xFF的范围内,加入192个字母及符号,藉以供使用变音符号的拉丁字母语言使用。从而支持德文,法文等。因而它依然是一个单字节编码,只是比ASCII更全面。
GB2312 中国的中文编码表。 英文占一个字节, 中文占两个字节。
GBK 中国的中文编码表升级,融合了更多的中文文字符号。
Unicode 国际标准码,融合了多种文字。所有文字都用两个字节来表示,Java语言使用的就是unicode。
UTF-8 英文占一个字节,中文占三个字节。 最多用三个字节来表示一个字符。
UTF-16 英文中文都是占两个字节。

2、特有方法:

1、write(int val) —> 写入一个字节(最低八位)

2、writeInt(int vale) —> 吸入一个32为int值

3、getBytes()、getBytes(encoding)函数的作用是使用系统默认或者指定的字符集编码方式,将字符串编码成字节数组。

注意:Unicode不是一个码表,只是一个规范。

3、使用步骤:

说明:serialVersion
a、给类一个可被编译器识别的的序列号,在编译类时,会分配一个long型UID,通过序列号,将类存入硬盘中,并序列化,即持久化。序列号根据成员算出的。静态不能被序列化。如果非静态成员也无需序列化,可以用transien修饰。

b、接口Serializable中没有方法,称之为标记接口

1、写入流对象:

1)创建对象写入流,与文件关联,即传入目的

2)通过写入writeObject()方法,将对象作为参数传入,即可写入文件

2、读取流对象

1)创建对象读取流,与文件关联,即传入源

2)通过writeObject()方法,读取文件中的对象,并返回这个对象

示例:

import java.io.*;  
//创建Person类,实现序列化  
class Person implements Serializable{  
    //定义自身的序列化方式  
    public static final long serialVersionUID = 42L;  
    //定义私有属性  
    private String name;  
    private int age;  
    transient String id;  
    static String country = "cn";  
    //构造Person类  
    Person(String name,int age,String id,String country){  
        this.name = name;  
        this.age = age;  
        this.id = id;  
        this.country = country;  
    }  
    //覆写toString方法  
    public String toString(){  
        return name+ ":" + age + ":" + id + ":" + country;  
    }  
}  
//对象序列化测试  
class ObjectStreamDemo{  
    public static void main(String[] args){  
        //对象写入流  
        writeObj();  
        //对象读取流  
        readObj();  
    }  
    //定义对象读取流  
    public static void readObj(){  
        ObjectInputStream ois = null;  
        try{  
            //创建对象读取流  
            ois = new ObjectInputStream(new FileInputStream("obj.txt"));  
            //通过读取文件数据,返回对象  
            Person p = (Person)ois.readObject();  
            System.out.println(p);  
        }catch (Exception e){  
            throw new RuntimeException("写入文件失败");  
        }  
        //最终关闭流对象  
        finally{  
            try{  
                if(ois!=null)  
                    ois.close();  
                }catch (IOException e){  
                throw new RuntimeException("写入流关闭失败");  
            }  
        }  
    }  
    //定义对象写入流  
    public static void writeObj(){  
        ObjectOutputStream oos = null;  
        try{  
            //创建对象写入流  
            oos = new ObjectOutputStream(new FileOutputStream("obj.txt"));  
            //写入对象数据  
            oos.writeObject(new Person("lisi",25,"01","cn"));             
        }catch (Exception e){  
            throw new RuntimeException("写入文件失败");  
        }  
        //关闭流资源  
        finally{  
            try{  
                if(oos!=null)  
                    oos.close();  
                }catch (IOException e){  
                throw new RuntimeException("写入流关闭失败");  
            }  
        }  
    }  
} 

编码方式决定字节长度;在中文平台下,默认的字符集编码是GBK,此时如果使用getBytes()或getBytes(“GBK”),则按照GBK的编码规则将每个中文字符用2个byte表示所以我们看到”中文”最终GBK编码结果就是: -42 -48
-50 -60
。-42和-48代表了”中”字,而”-50″和”-60″则代表了”文”字。

编码: 把看得懂的字符变成看不懂码值这个过程我们称作为编码。

二、管道流

在中文平台下,如果指定的字符集编码是UTF-8,那么按照UTF-8对中文的编码规则:每个中文用3个字节表示,那么”中文”这两个字符最终被编码成:-28
-72 -83、-26 -106 -121两组。每3个字节代表一个中文字符。

字符串—>字节数组String类的getBytes()
方法进行编码,将字符串转为对应的二进制,并且这个方法可以指定编码表。如果没有指定码表,该方法会使用操作系统默认码表。

1、概述:

1、管道流:PipedInputStream和PipedOutputStream

2、管道流涉及到多线程的问题

在中
文平台下,如果指定的字符集编码是ISO-8859-1,由于此字符集是单字节编码,所以使用getBytes(“ISO-8859-1”)时,每个字符
只取一个字节,每个汉字只取到了一半的字符。另外一半的字节丢失了。由于这一半的字符在字符集中找不到对应的字符,所以默认使用编码63代替,也就是?。

注意:中国大陆的Windows系统上默认的编码一般为GBK。在Java程序中可以使用System.getProperty(“file.encoding”)方式得到当前的默认编码。

2、使用步骤:

1、要先创建一个读和写的两个类,实现Runnable接口,因为是两个不同的线程,覆盖run方法,注意,需要在内部抛异常

2、创建两个管道流,并用connect()方法将两个流连接

3、创建读写对象,并传入两个线程内,并start执行

示例:

import java.io.*;  

//创建Read类,实现run方法  
class Read implements Runnable{  
    private PipedInputStream in;      
    Read(PipedInputStream in){  
        this.in = in;  
    }  
    //实现run方法  
    public void run(){  
        try{  
            //读取写入的数据  
            //System.out.println("开始写入数据,等待时间");//测试用  
            Thread.sleep(3000);  
            byte[] b = new byte[1024];  
            int len = in.read(b);  
            //System.out.println("读取完毕");//测试用  
            String s = new String(b,0,len);  
            System.out.println(s);  
            in.close();  
        }catch (Exception e){  
            throw new RuntimeException("管道流读取失败");  
        }  
    }  
}  
//创建Write类  
class Write implements Runnable{  
    private PipedOutputStream out;  
    //Write构造函数  
    Write(PipedOutputStream out){  
        this.out = out;  
    }  
    //实现run方法  
    public void run(){  
        try{  
            //写入数据  
            //System.out.println("开始写入数据");//测试用  
            out.write("管道流来喽~~~~".getBytes());  
            out.close();  
        }catch (IOException e){  
            throw new RuntimeException("管道流写入失败");  
        }  
    }  
}  
class PipedStreamDemo{  
    public static void main(String[] args) throws IOException  
    {  
        //创建管道流对象  
        PipedInputStream in = new PipedInputStream();  
        PipedOutputStream out = new PipedOutputStream();  
        //将读取流(输入流)和写入流(输出流)关联起来  
        in.connect(out);  
        //创建读写对象,并创建线程对象  
        Read r = new Read(in);  
        Write w = new Write(out);  
        new Thread(r).start();  
        new Thread(w).start();  
    }  
}

在英文平台下,默认的字符集编码是Cp1252(类似于ISO-8859-1),如果使用GBK、UTF-8进行编码,得到的字节数组依然是正确的(GBK4个字节,UTF-8是6个字节)。因为在JVM内部是以Unicode存储字符串的,使用getBytes(encoding)会让JVM进行一次Unicode到指定编码之间的转换。对于GBK,JVM依然会转换成4个字节,对于UTF-8,JVM依然会转换成6个字节。但是对于ISO-8859-1,则由于无法转换(2个字节—>1个字节,截取了一半的字节),所以转换后的结果是错误的。

解码:
把码值查找对应的字符,我们把这个过程称作为解码。字节数组—>字符串String类的构造函数完成。String(byte[]
bytes) 使用系统默认码表String(byte[],charset)指定码表

三、RandomAccessFile 类

 

注意:我们使用什么字符集进行编码,就应该使用什么字符集进行解码,否则很有可能出现乱码。

1、概述:

1、RandomAccessFile称之为随机访问文件的类,自身具备读写方法。

2、该类不算是IO体系中的子类,而是直接继承Object,但是它是IO包成员,因为它具备读写功能,内部封装了一个数组,且通过指针对数组的元素进行操作,同时可通过seek改变指针的位置。

3、可以完成读写的原理:内部封装了字节输入流

4、构造函数:RandomAccessFile(File file,String
mode),可已从它的构造函数中看出,该类只能操作文件(也有字符串),而且操作文件还有模式。

模式传入值:”r“:以只读方式打开;”rw“:打开以便读写

如果模式为只读,则不会创建文件,会去读一个已存在的文件,若文件不存在,则会出现异常,如果模式为rw,且该对象的构造函数要操作的文件不存在,会自动创建,如果存在,则不会覆盖,也可通过seek方法修改。

在中文平台下,默认的字符集编码是GBK,于是content.getBytes()得到的是什么呢?就是下面这4个字节:

public class Demo7 { public static void main(String[] args) throws Exception { /* String str = "中国"; // getBytes() :使用的是平台默认的编码表---gbk编码表。 一个中文占两个字节 byte[] buf = str.getBytes; //编码过程 System.out.println("数组的元素:"+Arrays.toString; str = new String(buf,"utf-8"); //默认使用了gbk码表去解码。 如果解码过程与编码是不一样的码表,就会产生乱码 System.out.println("解码后的字符串:"+ str); */ /*String str = "a中国"; //[-2,-1,0,97,78,45,86,-3] String str = "中国";//[-2,-1,78,45,86,-3] byte[] buf = str.getBytes("unicode"); //编码与解码的时候指定的码表是unicode,实际上是用了utf-16. System.out.println("数组的内容:"+ Arrays.toString; //[-2,-1,0,97,78,45,86,-3] */ //-2和-1是utf-16自己另外加的,作为UTF-16的标志 String str = "大家好"; byte[] buf = str.getBytes(); //使用平台默认的编码gbk进行编码,但是要以文件本身的编码为准 System.out.println("字节数组:"+ Arrays.toString; // -76, -13, -68, -46, -70, -61 str = new String(buf,"iso8859-1"); //乱码 大家好 //在iso8859-1码表中,每个数字都有对应不同的字符,是唯一一个填满了的码表 // 还原:使用这一串特殊的字符找回之前的数字,再使用gbk进行编码 byte[] buf2 = str.getBytes("iso8859-1"); str = new String(buf2,"gbk"); System.out.println; } }

2、特有方法:

1、seek(int n):设置指针,可以将指针设置到前面或后面

2、skipBytes(int n):跳过指定字节数,不可往前跳

byte[0] = -42 hex string
= ffffffd6

注意: 编码与解码一般都使用统一的码表。否则非常容易出乱码。

3、使用步骤:

1、创建RandomAccessFile对象

2、将数据写入到指定文件中

3、读取数据,读入到指定文件中

注意:尧都区后面的数据,需要调用数组指针,通过改变角标位置,取出相应的数据

a.调整对象的指针:seek()
b.跳过指定字节数

示例:

import java.io.*;  
//注:这几个函数内部都需要try,为测试,在函数上抛异常  
class RanAccFileDemo{  
    public static void main(String[] args) throws IOException{  
        //readRaf();  
        readRaf2();  
        //writeRaf();  
    }  
    //写入数据  
    public static void writeRaf()throws IOException{  
        //创建对象,写入数据  
        RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");  
        raf.write("王五".getBytes());  
        raf.writeInt(99);  
        raf.write("李四".getBytes());  
        raf.writeInt(97);  
        raf.close();  
    }  
    //读取数据  
    public static void readRaf()throws IOException{  
        //创建对象,读取数据  
        RandomAccessFile raf = new RandomAccessFile("ran.txt","r");  
        byte[] b = new byte[4];  
        raf.read(b);  
        String name = new String(b);  
        int age = raf.readInt();  
        System.out.println("name="+ name);  
        System.out.println("age=" + age);  
        raf.close();  
    }  
    //读取数据  
    public static void readRaf2()throws IOException {  
        //创建对象,读取数据  
        RandomAccessFile raf = new RandomAccessFile("ran.txt","r");  
        //调整对象中的指针  
        //raf.seek(8);  
        //跳过指定字节数  
        raf.skipBytes(8);  
        byte[] b = new byte[4];  
        raf.read(b);  
        String name = new String(b);  
        int age = raf.readInt();  
        System.out.println("name="+ name);  
        System.out.println("age=" + age);  
        raf.close();  
    }  
}

byte[1] = -48 hex string =
ffffffd0

不是所有的乱码都可以还原的:以上情况拿着数字去iso8859-1去找,因为该码表每个数字都有对应的字符,但是如果对于一些其他码表,对应的数字没有该字符,就会造成数据丢失。

四、操作基本数据类型的流对象

byte[2] = -50 hex string =
ffffffce

中文乱码问题是编码不一致导致的,只要保证了前端(页面使用meta标记utf-8),后端(对参数的解析、与连接库的连接),和数据库都使用统一的编码,一般不会出现乱码问题。

1、概述:

1、操作基本数据类型的流对象:DataInputStream和DataOutputStream

2、这两个读写对象,可用于操作基本数据类型的流对象,包含读写各种基本数据类型的方法

byte[3] = -60 hex string =
ffffffc4

①JSP页面

2、特有方法:

int型 writeInt(int n) int readInt()
boolean型 writeBoolean(boolean b) boolean readBoolean()
double型 writeDouble(double d) double readDouble()

如果新的encoding是GBK,那么经过解码后,由于一个字符用2个字节表示。于是最终的结果就是:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

五、操作数组和字符串

char[0]=’中’ — byte[0] +
byte[1]

相关文章

No Comments, Be The First!
近期评论
    功能
    网站地图xml地图