Java 中 I/O 进制详解及I/O流小结

在Java世界里,99%的工作都是处理这高层。那么二进制,字节码这些会在哪里用到呢?

自问自答:在 跨平台 的时候,就凸显神功了。比如说 文件读写 , 数据通信 ,还有Java编译后的 字节码文件 。下面会有个数据通信的例子哦。

Java对对象实现 Serializablle 接口,就可以将其转化为一系列 字节 ,而在通信中,不必要关系数据如何在不同机器表示和字节的顺序。这里泥瓦匠对 Serializablle 接口,不做详细讲解,以后单独详解。

Java进制转换

首先认识下Java中的 数据类型 :

    1、Int整型:byte(8位,-128~127)、short(16位)、int(32位)、long(64位)

    2、Float型:float(32位)、double(64位)

    2、char字符:unicode字符(16位)

也就是说, 一个int等价于长度为4的字节数组。

Java中进制如何转换呢?

在Java中,Int整形以及char字符型 被包装的类 中提供了一系列的 操作方法 。比如 java.lang.Integer 中 , api如图所示 :

下面泥瓦匠写个demo,验证下。

package javaBasic.oi.byteoper;

public class IntegerOper
{
    public static void main(String[] args)
    {
        System.out.println("17的十六进制: " + Integer.toHexString(17));
        System.out.println("17的八进制:     "     + Integer.toOctalString(17));
        System.out.println("17的二进制:     "     + Integer.toBinaryString(17));

        System.out.println(Integer.valueOf("11", 16));
        System.out.println(Integer.valueOf("21", 8));
        System.out.println(Integer.valueOf("00010001", 2));
    }
}

右键Run一下,我们可以在控制台中看到如下输出:

的十六进制: 11
的八进制:   21
的二进制:   10001

补充: 如果值太大,则需要调用 java.lang.Long 提供的方法。

Java基本类型和字节神奇转换

这里泥瓦匠想到了自己是个学生,典型的 OO 思想。那学号:1206010035是整型,怎么转成字节呢,上面说的拥有字节码的对象能通信。所以,学校关于学号这个都是这样的方式通信的。因此,要将学号转成字节码才行。

泥瓦匠就写了个工具类 IntegerConvert.java:

package javaBasic.oi.byteoper;

public class IntegerConvert
{
    /**
     * Int转字节数组
     */
    public static byte[] int2Bytes(int inta)
    {
        // 32位Int可存于长度为4的字节数组
        byte[] bytes = new byte[4];
        for (int i = 0; i < bytes.length; i++)
            bytes[i] = (byte)(int)((inta >> i * 8) & 0xff);// 移位和清零
        
        return bytes;
    }
    
    /**
     * 字节数组转Int
     */
    public static int bytes2Int(byte[] bytes)
    {
        int inta = 0;
        for (int i = 0; i < bytes.length; i++)
            inta += (int)((bytes[i] & 0xff) << i * 8);// 移位和清零
        
        return inta;
    }
    
    public static void main(String[] args)
    {
        // 将我的学号转换成字节码
        byte[] bytes = IntegerConvert.int2Bytes(1206010035);
        System.out.println(bytes[0] + " " + bytes[1] + " " + bytes[2] + " " + bytes[3]);
        // 字节码就可以转换回学号
        System.out.println(IntegerConvert.bytes2Int(bytes));
    }

}

跑一下,右键Run,可以看到以下输出:

-77 64 -30 71
010035

代码详细解释如下:

    1、(inta >> i * 8) & 0xff

    移位 清零从左往右,按8位获取1字节 。

    2、这里使用的是 小端法 。地位字节放在内存低地址端,即该值的起始地址。补充:32位中分大端模式(PPC)和小段端模式(x86)。

自然,Long也有其转换方法,如下:

public class LongConvert
{
    /**
     * long 转 byte数组
     */
    public static byte[] long2Bytes(long longa)
    {
        byte[] bytes = new byte[8];
        for (int i = 0; i < bytes.length; i++)
            bytes[i] = (byte)(long)(((longa) >> i * 8) & 0xff); // 移位和清零
        
        return bytes;
    }
    
    /**
     * byte数组 转 long
     */
    public static long bytes2Long(byte[] bytes)
    {
        long longa = 0;
        for (int i = 0; i < bytes.length; i++)
            longa += (long)((bytes[i] & 0xff) << i * 8); // 移位和清零
        
        return longa;
    }
    
}

那字符串,字符数组呢?比如泥瓦匠的名字:李强强

Java也提供了一系列的方法,其实 java.lang.String 封装了 char[] ,其中本质还是 对char数组的操作 。代码如下:

package javaBasic.oi.byteoper;

public class StringConvert
{
    public static void main(String[] args)
    {
        String str = "李强强";
        byte[] bytes = str.getBytes();
        // 打印字节数组
        System.out.println("'李强强'的字节数组为:");
        for (int i = 0; i < bytes.length; i++)
            System.out.print("\t" + bytes[i]);
    }
}

右键Run一下,可以看到以下输出:

'李强强'的字节数组为:
    -64    -18    -57    -65    -57    -65

论证 :这里我们论证了一个中文,需要 两个字节 表示,也就是说 一个中文是16位 。

浅谈Java通信中的数据

下面简单把泥瓦匠学生的故事延续。 

如图,库表中一个学生对象,有个属性是学号。这时候客户端要向服务端发送这个对象。过程如下:

    1、对象实现Serializable接口。

    实现了 Serializable接口 的对象,可将它们转换成一系列字节,并可在以后完全恢复回原来的样子。

    2、其学号属性值 1206010035,由客户端转换为字节码。

    3、字节码传输至服务端

    4、服务端接收并转换为对象属性值。

 java中的I/O流小结

java.io包中约有75个类和接口。 java.io包设计的目的是处理数据和对象的IO操作。程序员需要使用java.io包把数据写到磁盘文件,套接子,URL,以及系统控制台上,并从中读取输入数据。java.io包也支持字符串数据的格式化处理,以及zip和jar文本处理。

java中的I/O操作大量采用包装处理,因此需要执行两到三个类才能实现简单的I/O处理。

所谓包装(wrapper)就是通过其他对象才能访问自己特性的对象。包装对对象将会增强或改善被包装对象的可用性。Java I/O库广泛采用此技术。包装是一种设计模式,这种设计模式也成为“装饰”(decorator)设计模式。java中的流采用包装主要是提高读取或者输出数据的效率。

java中有两种流,字节流和字符流。每种流又分为输入流和输出流。那么在进行I/O操作时候如何选择使用字节流还是字符流呢?

以输出为例,主要从一下三个方面解决

1.确定输出内容是否包含任何字符。如果包括字符,是输出16位编码的字符还是输出8位编码的字符?

如果在美国或欧洲打印一个报表,也许需要选用8位编码的字符输出。如果有一个使用了16位Unicode字符的数据库,则应选用16位编码的字符输出。注意在做出选择时不应该破坏数据。

1)选用8位编码的字符输出时,应用OutputStream(默认情况)

2)选用16位编码的字符输出时,应用Writer类。

2. 确定数据输出的目的

JAVA程序访问外部数据是通过数据流实现的。大多数物理输出目的都有一个专门的底层类可用
基于输出目的和数据宽度确定底层类 输出目的     输出8位字符的OutputStream类或方法     输出16位字符的Writer类
文件     java.io.FileOutputStream     java.io.FileWriter
套接子     java.net.Socket.getOutputStream()     套接子从不使用16位编码的数据流
URL(GET/POST)     java.net.URLConnection.getOutputStream()     URL建立在套接子基础上,所以无
管道     java.io.PipedOutputStream     java.io.PipedWriter
内存中的数组     java.io.ByteArrayOutputStream     java.io.CharArrayWriter

3. 确定输出数据类型,二进制数据?还是可打印的数据?

根据二进制数据,ASCII字符和字符串输出之间的不同确定顶层类 类型     格式     十六进制数值     用到的类
二进制数据     4字节的二进制整数           java.io.DataOutputStream
ASCII字符     连续的字节           

    java.io.PrintOutputStream

字符串     连续的双字节字符           java.io.PrintWriter

我们把这一步选用的类成为顶层类。

举个例子

假定有一个数组,其中包含1000个整数值,我们想以二进制数据形式把它们写到一个文件中代码如下

FileOutputStream fos = new FileOutputStream("ints.dat");

DataOutputStrea dos = new DataOutputStream(fos);

for (int i=0;i<1000;i++){

dow.writeInt(myArray[i])

}

dos.close();

时间: 2024-08-11 06:54:02

Java 中 I/O 进制详解及I/O流小结的相关文章

Java I/O : Java中的进制详解

作者:李强强 上一篇,泥瓦匠基础地讲了下Java I/O : Bit Operation 位运算.这一讲,泥瓦匠带你走进Java中的进制详解. 一.引子 在Java世界里,99%的工作都是处理这高层.那么二进制,字节码这些会在哪里用到呢? 自问自答:在跨平台的时候,就凸显神功了.比如说文件读写,数据通信,还有Java编译后的字节码文件.下面会有个数据通信的例子哦. Java对对象实现Serializablle接口,就可以将其转化为一系列字节,而在通信中,不必要关系数据如何在不同机器表示和字节的顺

多用多学之Java中的Set,List,Map详解_java

很长时间以来一直代码中用的比较多的数据列表主要是List,而且都是ArrayList,感觉有这个玩意就够了.ArrayList是用于实现动态数组的包装工具类,这样写代码的时候就可以拉进拉出,迭代遍历,蛮方便的. 也不知道从什么时候开始慢慢的代码中就经常会出现HashMap和HashSet之类的工具类.应该说HashMap比较多一些,而且还是面试经典题,平时也会多看看.开始用的时候简单理解就是个键值对应表,使用键来找数据比较方便.随后深入了解后发现 这玩意还有点小奥秘,特别是新版本的JDK对Has

关于java中构造函数的一些知识详解_java

java的构造函数是一个非常重要的作用,首先java里的构造函数是可以重载的,而且因为也是可以继承在父类的构造函数,所以在子类里,首先必然是调用父类的构造函数.可以看下面的两个例子来对比: public class Test { public static void main(String args[]) { B b = new B(100); } } class A { public A() { System.out.println("A without any parameter"

java中queue接口的使用详解_java

Queue接口与List.Set同一级别,都是继承了Collection接口.LinkedList实现了Queue接口.Queue接口窄化了对LinkedList的方法的访问权限(即在方法中的参数类型如果是Queue时,就完全只能访问Queue接口所定义的方法 了,而不能直接访问 LinkedList的非Queue的方法),以使得只有恰当的方法才可以使用.BlockingQueue 继承了Queue接口.  队列是一种数据结构.它有两个基本操作:在队列尾部加人一个元素,和从队列头部移除一个元素就

java中set接口使用方法详解_java

java中的set接口有如下的特点: 不允许出现重复元素: 集合中的元素位置无顺序: 有且只有一个值为null的元素. 因为java中的set接口模仿了数学上的set抽象,所以,对应的数学上set的特性为: 互异性:一个集合中,任何两个元素都认为是不相同的,即每个元素只能出现一次.无序性:一个集合中,每个元素的地位都是相同的,元素之间是无序的.集合上可以定义序关系,定义了序关系后,元素之间就可以按照序关系排序.但就集合本身的特性而言,元素之间没有必然的序.空集的性质:空集是一切集合的子集    

Java中的迭代和递归详解_java

前言 最近在看书的时候看到这一内容,感觉还是蛮有收获的.迭代使用的是循环(for,while,do...wile)或者迭代器,当循环条件不满足时退出.而递归,一般是函数递归,可以是自身调用自身,也可以是非直接调用,即方法A调用方法B,而方法B反过来调用方法A,递归退出的条件为if,else语句,当条件符合基的时候退出. 上面是迭代和递归的语法特性,他们在Java中有什么不同呢?下面通过这篇文章来详细了解了解. 一.递归 提到迭代,不得不提一个数学表达式: n!=n*(n-1)*(n-2)*...

Java 中的字符串常量池详解_java

Java中的字符串常量池 Java中字符串对象创建有两种形式,一种为字面量形式,如String str = "droid";,另一种就是使用new这种标准的构造对象的方法,如String str = new String("droid");,这两种方式我们在代码编写时都经常使用,尤其是字面量的方式.然而这两种实现其实存在着一些性能和内存占用的差别.这一切都是源于JVM为了减少字符串对象的重复创建,其维护了一个特殊的内存,这段内存被成为字符串常量池或者字符串字面量池.

Java中对象序列化与反序列化详解_java

本文实例讲述了Java中对象序列化与反序列化.分享给大家供大家参考.具体如下: 一.简介 对象序列化(Serializable)是指将对象转换为字节序列的过程,而反序列化则是根据字节序列恢复对象的过程. 序列化一般用于以下场景: 1.永久性保存对象,保存对象的字节序列到本地文件中: 2.通过序列化对象在网络中传递对象: 3.通过序列化在进程间传递对象. 对象所属的类必须实现Serializable或是Externalizable接口才能被序列化.对实现了Serializable接口的类,其序列化

java中vector与hashtable操作详解

众所周知,java中vector与hashtable是线程安全的,主要是java对两者的操作都加上了synchronized,也就是上锁了.因此 在vector与hashtable的操作是不会出现问题.但是有一种情况:就是将一个hashtable copy到另一个hashtable时,假如使用putAll方法的花,会抛出一个 java.util.ConcurrentModificationException异常.先上代码: TestSync.java  代码如下 复制代码   public cl