IT学习笔记(四)(第三部分)(持续更新)

64. File类可以描述一个文件或者一个文件夹。
File类的构造方法:

    File(String pathname)  指定文件或者文件夹的路径创建一个File文件。
    File(File parent, String child)   根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例。 

    File(String parent, String child) 

目录分隔符:  在windows机器上 的目录分隔符是 \  ,在linux机器上的目录分隔符是/ .

注意:  在windows上面\ 与 / 都可以使用作为目录分隔符。 而且,如果写/ 的时候只需要写一个即可。

路径问题: 

绝对路径: 该文件在硬盘上 的完整路径。绝对路径一般都是以盘符开头的。

相对路径:  相对路径就是资源文件相对于当前程序所在的路径。

 . 当前路径
 
 .. 上一级路径
 
注意: 如果程序当前所在的路径与资源文件不是在同一个盘下面,是没法写相对路径 的。

 创建:
    createNewFile()    在指定位置创建一个空文件,成功就返回true,如果已存在就不创建然后返回false
    mkdir()            在指定位置创建目录,这只会创建最后一级目录,如果上级目录不存在就抛异常。
    mkdirs()        在指定位置创建目录,这会创建路径中所有不存在的目录。
    renameTo(File dest)    重命名文件或文件夹,也可以操作非空的文件夹,文件不同时相当于文件的剪切,剪切时候不能操作非空的文件夹。移动/重命名成功则返回true,失败则返回false。

注意:renameTo()  如果目标文件与源文件是在同一个路径下,那么renameTo的作用是重命名, 如果目标文件与源文件不是在同一个路径下,那么renameTo的作用就是剪切,而且还不能操作文件夹。

删除:
delete()        删除文件或一个空文件夹,如果是文件夹且不为空,则不能删除,成功返回true,失败返回false。
deleteOnExit()    在虚拟机终止时,请求删除此抽象路径名表示的文件或目录,保证程序异常时创建的临时文件也可以被删除。

判断:
        exists()        文件或文件夹是否存在。
        isFile()        是否是一个文件,如果不存在,则始终为false。
        isDirectory()    是否是一个目录,如果不存在,则始终为false。
        isHidden()        是否是一个隐藏的文件或是否是隐藏的目录。
        isAbsolute()    测试此抽象路径名是否为绝对路径名。

 获取:
    getName()        获取文件或文件夹的名称,不包含上级路径。
    getPath()       返回绝对路径,可以是相对路径,但是目录要指定
    getAbsolutePath()    获取文件的绝对路径,与文件是否存在没关系
    length()        获取文件的大小(字节数),如果文件不存在则返回0L,如果是文件夹也返回0L。
    getParent()        返回此抽象路径名父目录的路径名字符串;如果此路径名没有指定父目录,则返回null。
    lastModified()    获取最后一次被修改的时间。

文件夹相关:
    staic File[] listRoots()    列出所有的根目录(Window中就是所有系统的盘符)
    list()                        返回目录下的文件或者目录名,包含隐藏文件。对于文件这样操作会返回null。
    listFiles()                    返回目录下的文件或者目录对象(File类实例),包含隐藏文件。对于文件这样操作会返回null。
    list(FilenameFilter filter)    返回指定当前目录中符合过滤条件的子文件或子目录。对于文件这样操作会返回null。
    listFiles(FilenameFilter filter)    返回指定当前目录中符合过滤条件的子文件或子目录。对于文件这样操作会返回null。

65. 计算机网络: 分布在不同地域 的计算机通过外部设备链接起来达到了消息互通、资源共享的效果就称作为一个计算机网络。

网络通讯的三要素:
    1) IP        2) 端口号       3) 协议。

IP地址的本质就是一个由32位的二进制数据组成的数据。 后来别人为了方便我们记忆IP地址,就把IP地址切成了4份,每份8bit.   2^8 = 0~255。

IP地址 = 网络号+ 主机号。
IP地址的分类:
    A类地址 = 一个网络号 + 三个主机号     2^24   政府单位
    B类地址 =  两个网络号+ 两个主机号   2^16 事业单位(学校、银行..)
    C类地址= 三个网络号+ 一个主机号  2^8    私人使用

InetAddress(IP类)
常用的方法:
    getLocalHost();  获取本机的IP地址
    getByName("IP或者主机名") 根据一个IP地址的字符串形式或者是一个主机名生成一个IP地址对象。 (用于获取别人的IP地址对象)
    getHostAddress()  返回一个IP地址的字符串表示形式。
    getHostName()  返回计算机的主机名。

端口号是没有类描述的。
    端口号的范围: 0~65535
        从0到1023,系统紧密绑定于一些服务。 
        1024~65535  我们可以使用

网络通讯的协议:
  (1) udp通讯协议
    UDP通讯协议的特点:
    1) 将数据极封装为数据包,面向无连接。
    2) 每个数据包大小限制在64K中
    3)因为无连接,所以不可靠
    4) 因为不需要建立连接,所以速度快
    5)udp 通讯是不分服务端与客户端的,只分发送端与接收端。

udp协议下的Socket:    
    DatagramSocket(udp插座服务)
    DatagramPacket(数据包类)
        DatagramPacket(buf, length, address, port)
        buf: 发送的数据内容
        length : 发送数据内容的大小。
        address : 发送的目的IP地址对象
        port : 端口号。

发送端的使用步骤:
    1) 建立udp的服务。
    2) 准备数据,把数据封装到数据包中发送。 发送端的数据包要带上ip地址与端口号。
    3) 调用udp的服务,发送数据。
    4) 关闭资源。

//发送端
public class Demo1Sender {
	
	public static void main(String[] args) throws IOException {
		//建立udp的服务
		DatagramSocket datagramSocket = new DatagramSocket();
		//准备数据,把数据封装到数据包中。
		String data = "这个是我第一个udp的例子..";
		//创建了一个数据包
		DatagramPacket packet = new DatagramPacket(data.getBytes(), data.getBytes().length,InetAddress.getLocalHost() , 9090);
		//调用udp的服务发送数据包
		datagramSocket.send(packet);
		//关闭资源 ---实际上就是释放占用的端口号
		datagramSocket.close();		
	}
}

接收端的使用步骤
     1) 建立udp的服务
     2) 准备空 的数据 包接收数据。
     3) 调用udp的服务接收数据。
     4) 关闭资源

public class Demo1Receive {

	public static void main(String[] args) throws IOException {
		//建立udp的服务 ,并且要监听一个端口。
		DatagramSocket  socket = new DatagramSocket(9090);
		
		//准备空的数据包用于存放数据。
		byte[] buf = new byte[1024];
		DatagramPacket datagramPacket = new DatagramPacket(buf, buf.length); // 1024
		//调用udp的服务接收数据
		socket.receive(datagramPacket); //receive是一个阻塞型的方法,没有接收到数据包之前会一直等待。 数据实际上就是存储到了byte的自己数组中了。
		System.out.println("接收端接收到的数据:"+ new String(buf,0,datagramPacket.getLength())); // getLength() 获取数据包存储了几个字节。
		//关闭资源
		socket.close();		
	}	
}

 tcp通讯协议。

66. Java NIO

Java NIO(New IO)是一个可以替代标准Java IO API的IO API(从Java 1.4开始),Java NIO提供了与标准IO不同的IO工作方式。

Java NIO 由以下几个核心部分组成:

  • Channels
  • Buffers
  • Selectors

基本上,所有的 IO 在NIO 中都从一个Channel 开始。Channel 有点象流。 数据可以从Channel读到Buffer中,也可以从Buffer 写到Channel中。

Channel和Buffer有好几种类型。下面是JAVA NIO中的一些主要Channel的实现:

  • FileChannel
  • DatagramChannel
  • SocketChannel
  • ServerSocketChannel

正如你所看到的,这些通道涵盖了UDP 和 TCP 网络IO,以及文件IO。

以下是Java NIO里关键的Buffer实现:

  • ByteBuffer
  • CharBuffer
  • DoubleBuffer
  • FloatBuffer
  • IntBuffer
  • LongBuffer
  • ShortBuffer

这些Buffer覆盖了你能通过IO发送的基本数据类型:byte, short, int, long, float, double 和 char。

Selector允许单线程处理多个 Channel。如果你的应用打开了多个连接(通道),但每个连接的流量都很低,使用Selector就会很方便。例如,在一个聊天服务器中。

这是在一个单线程中使用一个Selector处理3个Channel的图示:

要使用Selector,得向Selector注册Channel,然后调用它的select()方法。这个方法会一直阻塞到某个注册的通道有事件就绪。一旦这个方法返回,线程就可以处理这些事件,事件的例子有如新连接进来,数据接收等。

Buffer介绍:

ava NIO中的Buffer用于和NIO通道进行交互;如你所知,数据是从通道读入缓冲区,从缓冲区写入到通道中的。缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存。这块内存被包装成NIO Buffer对象,并提供了一组方法,用来方便的访问该块内存。

它的三个属性:

  • capacity:作为一个内存块,Buffer有一个固定的大小值,也叫“capacity”.你只能往里写capacity个byte、long,char等类型。一旦Buffer满了,需要将其清空(通过读数据或者清除数据)才能继续写数据往里写数据。
  • position:

    当你写数据到Buffer中时,position表示当前的位置。初始的position值为0.当一个byte、long等数据写到Buffer后, position会向前移动到下一个可插入数据的Buffer单元。position最大可为capacity – 1.

    当读取数据时,也是从某个特定位置读。当将Buffer从写模式切换到读模式,position会被重置为0. 当从Buffer的position处读取数据时,position向前移动到下一个可读的位置。

  • limit:

    在写模式下,Buffer的limit表示你最多能往Buffer里写多少数据。 写模式下,limit等于Buffer的capacity。

    当切换Buffer到读模式时, limit表示你最多能读到多少数据。因此,当切换Buffer到读模式时,limit会被设置成写模式下的position值。换句话说,你能读到之前写入的所有数据(limit被设置成已写数据的数量,这个值在写模式下就是position)

Java NIO 有以下Buffer类型

  • ByteBuffer
  • MappedByteBuffer
  • CharBuffer
  • DoubleBuffer
  • FloatBuffer
  • IntBuffer
  • LongBuffer
  • ShortBuffer

几个常用方法: 

(1)Buffer的分配:要想获得一个Buffer对象首先要进行分配。

1)使用allocate()静态方法。每一个Buffer类都有一个allocate方法。下面是一个分配48字节capacity的ByteBuffer的例子。

1 ByteBuffer buf = ByteBuffer.allocate(48);

这是分配一个可存储1024个字符的CharBuffer:

1 CharBuffer buf = CharBuffer.allocate(1024);

2)通过包装一个已有的数组来创建
    如下,通过包装的方法创建的缓冲区保留了被包装数组内保存的数据.
    ByteBuffer buffer=ByteBuffer.wrap(byteArray);

    如果要将一个字符串存入ByteBuffer,可以如下操作:
    String sendString="你好,服务器. ";
    ByteBuffer sendBuffer=ByteBuffer.wrap(sendString.getBytes("UTF-16")); 

(2)写数据到Buffer有两种方式:

  • 从Channel写到Buffer。
  • 通过Buffer的put()方法写到Buffer里。

从Channel写到Buffer的例子:

 
RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt""rw");
  FileChannel inChannel = aFile.getChannel();

int bytesRead = inChannel.read(buf); //read into buffer.

通过put方法写Buffer的例子:

1 buf.put(127);

 (3)flip ()

flip方法将Buffer从写模式切换到读模式。调用flip()方法会将position设回0,并将limit设置成之前position的值。

换句话说,position现在用于标记读的位置,limit表示之前写进了多少个byte、char等 —— 现在能读取多少个byte、char等。

(4)从Buffer中读取数据有两种方式:

  • 从Buffer读取数据到Channel。
  • 使用get()方法从Buffer中读取数据。

从Buffer读取数据到Channel的例子:

1 //read from buffer into channel.
2 int bytesWritten = inChannel.write(buf);

使用get()方法从Buffer中读取数据的例子

1 byte aByte = buf.get();

(5)rewind()

Buffer.rewind()将position设回0,所以你可以重读Buffer中的所有数据。limit保持不变,仍然表示能从Buffer中读取多少个元素(byte、char等)。

(6)clear()和compact()

一旦读完Buffer中的数据,需要让Buffer准备好再次被写入。可以通过clear()或compact()方法来完成。

如果调用的是clear()方法,position将被设回0,limit被设置成 capacity的值。换句话说,Buffer 被清空了。Buffer中的数据并未清除,只是这些标记告诉我们可以从哪里开始往Buffer里写数据。如果Buffer中有一些未读的数据,调用clear()方法,数据将“被遗忘”,意味着不再有任何标记会告诉你哪些数据被读过,哪些还没有。

如果Buffer中仍有未读的数据,且后续还需要这些数据,但是此时想要先先写些数据,那么使用compact()方法。compact()方法将所有未读的数据拷贝到Buffer起始处。然后将position设到最后一个未读元素正后面。limit属性依然像clear()方法一样,设置成capacity。现在Buffer准备好写数据了,但是不会覆盖未读的数据。

(7)ByteBuffer.remaining(),此方法最给力,返回剩余的可用长度,此长度为实际读取的数据长度,最大自然是底层数组的长度。于是这样看来这个ByteBuffer更像是一个可标记的流。

关于Java NIO 系列教程可访问参看学习这个链接: Java NIO 系列教程

67. 无界非阻塞队列ConcurrentLinkedQueue

一个基于链接节点的无界线程安全队列。此队列按照 FIFO(先进先出)原则对元素进行排序。队列的头部 是队列中时间最长的元素。队列的尾部 是队列中时间最短的元素。
新的元素插入到队列的尾部,队列获取操作从队列头部获得元素。当多个线程共享访问一个公共 collection 时,ConcurrentLinkedQueue 是一个恰当的选择。此队列不允许使用 null 元素。适用于超高并发的场景,但是需要针对数据不一致采取一些措施。

几个常用方法:

(1)offer(E e) 
  将指定元素插入此队列的尾部。offer是往队列添加元素。

(2)poll() 
  获取并移除此队列的头,如果此队列为空,则返回 null。poll是从队列取出元素并且删除该元素。

(3)add()  

  ConcurrentLinkedQueue中的add() 和 offer() 完全一样,都是往队列尾部添加元素.

 (4)peek() 
   获取但不移除此队列的头;如果此队列为空,则返回 null。

(5)remove(Object o) 
  从队列中移除指定元素的单个实例(如果存在)。remove一个已存在元素,会返回true,remove不存在元素,返回false。

(6)size() 
   返回此队列中的元素数量 。注意:如果此队列包含的元素数大于 Integer.MAX_VALUE,则返回 Integer.MAX_VALUE。 需要小心的是,与大多数 collection 不同,此方法不是 一个固定时间操作。由于这些队列的异步特性,确定当前的元素数需要进行一次花费 O(n) 时间的遍历。 所以在需要判断队列是否为空时,尽量不要用 queue.size()>0,而是用 !queue.isEmpty()。

(7)contains(Object o) 
  如果此队列包含指定元素,则返回 true。

(8)toArray() 
  返回以恰当顺序包含此队列所有元素的数组。而toArray(T[] a) 返回以恰当顺序包含此队列所有元素的数组;返回数组的运行时类型是指定数组的运行时类型。

68. 使用SAXReader解析xml数据

  • 简单的学习一下xml,在w3school上看看就可以了:http://www.w3school.com.cn/xml/index.asp
  • 看一下xml和Json之间的对比和差别,这篇博客写的还是很详细的:http://www.cnblogs.com/SanMaoSpace/p/3139186.html
  • 知乎的这个问题也不错,学习学习涨姿势:https://www.zhihu.com/question/25636060

下面就说说怎么使用SAXReader来解析xml格式的数据吧。

首先当然是要导入dom4j的jar包了。我们来造一个测试用的xml文档,好像一般入门的测试数据都是这个book.xml,我们也拿这个来简单学习一下吧。

book.xml数据如下:

<books>
    <book>
        <author>Thomas</author>
        <title>Java从入门到放弃</title>
        <publisher>UCCU</publisher>
    </book>
    <book>
        <author>小白</author>
        <title>MySQL从删库到跑路</title>
        <publisher>Go Die</publisher>
    </book>
    <book>
        <author>PHPer</author>
        <title>Best PHP</title>
        <publisher>PHPchurch</publisher>
    </book>
</books>

我把book.xml放在D盘的根目录下,这样读取时能比较方便些……

下面是代码:

package com;
 
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
 
import java.io.ByteArrayInputStream;
import java.io.File;
import java.util.List;
 
public class SAXReaderXML {
    public static void main(String[] args) throws Exception {
        SAXReader reader = new SAXReader();
        File xmlfile = new File("D:/books.xml");
        String xml = "<books><book><author>Thomas</author><title>Java从入门到放弃</title><publisher>UCCU</publisher>" +
                "</book><book><author>小白</author><title>MySQL从删库到跑路</title><publisher>GoDie</publisher></book>" +
                "<book><author>PHPer</author><title>BestPHP</title><publisher>PHPchurch</publisher></book></books>";
        Document fileDocument = reader.read(xmlfile);//从xml文件获取数据
        Document document = reader.read(new ByteArrayInputStream(xml.getBytes("utf-8")));//读取xml字符串,注意这里要转成输入流
        Element root = document.getRootElement();//获取根元素
        List<Element> childElements = root.elements();//获取当前元素下的全部子元素
 
        for (Element child : childElements) {//循环输出全部book的相关信息
            List<Element> books = child.elements();
            for (Element book : books) {
                String name = book.getName();//获取当前元素名
                String text = book.getText();//获取当前元素值
                System.out.println(name + ":" + text);
            }
        }
        //获取第二条书籍的信息
        Element book2 = childElements.get(1);
        Element author = book2.element("author");//根据元素名获取子元素
        Element title = book2.element("title");
        Element publisher = book2.element("publisher");
        System.out.println("作者:" + author.getText());//获取元素值
        System.out.println("书名:" + title.getText());
        System.out.println("出版社:"+publisher.getText());
    }
}

代码解析:

1)读取xml数据

SAXReader可以通过多种方式读取xml数据,并返回Document格式的对象。通过查看源码,可以看出read()方法接收File,InputStream和URL等格式的参数来读取相应的xml数据。在代码里我演示了读取xml文档和xml格式的字符串两种方式。当然,字符串要根据相应的编码转成输入流才能被SAXReader读取。

2)解析xml数据

读取到Document对象后,我们使用getRootElement()方法获取根元素,返回的是一个Element对象。在本例中,该元素的name即为books。

3)获取子元素数据

获取根元素后,便可以一层一层的去获取他的子元素信息。如果知道子元素的标签名称,便可以直接调用element("name")方法获取该子元素。如果不知道子元素的名称,或者想直接获取该元素下的全部子元素,可以调用elements()方法获取一个包括全部元素的list,然后进行下一步的处理。

4)输出元素信息

调用getName()方法获取当前元素的元素名,attributeValue()获取属性名。如果当前元素没有子元素,则调用getText()方法获取元素值。

猜你喜欢

转载自blog.csdn.net/xudasong123/article/details/81106712