`
guoyunsky
  • 浏览: 854086 次
  • 性别: Icon_minigender_1
  • 来自: 上海
博客专栏
3d3a22a0-f00f-3227-8d03-d2bbe672af75
Heritrix源码分析
浏览量:206214
Group-logo
SQL的MapReduce...
浏览量:0
社区版块
存档分类
最新评论

Java多线程环境下如何高效安全处理数据(输入输出流、文件、网络等)(一)

    博客分类:
  • java
阅读更多

      本博客属原创文章,欢迎转载!转载请务必注明出处:http://guoyunsky.iteye.com/blog/867469

   

  这个标题可能有些歧义,我也不知道该取什么标题,知道的同学帮忙取下.同时这只是我平时的一个总结,
问题估计会有很多,大家帮忙指正,谢谢!
这里先说下应用场景,比如:
   1)需要一直处理一个文件目录,处理里面的文件.文件过多,单线程恐怕速度跟不上,于是使用多线程.
    2)网络下载,需要下载很多URL.单线程也是速度跟不上,于是一个URL用一个线程去下载并处理(如爬虫,这也是我写爬虫的总结).
 
再说下如何高效安全:
    1)以上不可能每一个文件,每一个URL就开一个线程去处理.肯定是先初始化一个线程池,然后将文件、URL放入一个容器(比如队列),然后线程从容器里获取数据去处理,处理完了,就再获取,如此直到处理完毕.
    2)可能文件或者URL的数据会很大,足让你内存溢出.或者多个线程的数据加起来也足以让你内存爆掉.那肯定要设置内存装载的数据大小限制,也就是所谓的缓存。当缓存写满了,再考虑写入文件.
    3)由于线程固定,缓存也是固定,写入的文件也是固定.那这些都是可循环利用的对象。不可能每一次处理都是new,那是极大的浪费。所以可以固定线程的个数,缓存的大小(可以控制内存大小),甚至那个备份文件也是一直可以循环所有的对象
  
所需要的东西:
    1)干活的线程
    2)接活的容器
    3)线程池
    4)可将数据放入内存达到一定阀值后再写入文件的类,同时提供返回数据的功能(内存和文件里的数据都得返回).返回数据也有多种形式,字符串、流?同时也得考虑循环利用,毕竟也是固定的
   5)附加功能:
         a.内容可以指纹化(MD5或SHA1)
         b.可以如InputStream的mark,reset等.毕竟这一切都可以当做输入输出流来处理,我接下来的代码也是
         c.可以控制处理的速度,比如这个场景是下载URL(网络爬虫),我不想下载速度过快.
         d.待补充

 

大概的设计:
   1)干活的线程 MyThread
   2)接活的容器 具体看你的应用,例子里有
    3)线程池   具体也看你的应用,我这里只是测试代码里弄个线程组
    4)处理数据的类:
          a.读数据到内存或文件中的类:MyOutputStream
          b.MyOutputStream里面又要返回数据的类:MyInputStream

 

接下来开始贴代码了.

1)可以读取数据,如果数据过多达到缓存,可以写入文件的类

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class MyOutputStream extends OutputStream {
    private boolean isOpen;         // 是否已经打开
    private long size;              // 数据总大小
    private String backedFileName;  // 超出缓存,要写入到的文件名
    private OutputStream diskStream;// 超出缓存,写入到文件的OutputStream
    private byte[] buffer;          // 缓存
    private long position;          // 当前位置
    private boolean recording;      // 是否记录数据中
    
    
    public MyOutputStream(int bufferSize,String backedFileName){
        this.buffer=new byte[bufferSize];
        this.backedFileName=backedFileName;
        this.recording=true;
    }
    
    public void open() throws IOException{
        if(isOpen()){
            throw new IOException("MyOutputStream already open for ".concat(Thread.currentThread().getName()));
        }
        isOpen=true;
        this.position=0;
        this.size=0;
        this.recording=true;
        
        closeDiskStream();
        
        this.diskStream=new FileOutputStream(this.backedFileName);
        
    }
    
    private void closeDiskStream() throws IOException{
        if(this.diskStream!=null){
            diskStream.close();
            diskStream=null;
        }
    }
    
    public void closeRecorder() throws IOException{
        recording=false;
        closeDiskStream();
        if(this.size==0){
            this.size=position;
        }
    }
    
    public boolean isOpen(){
        return isOpen;
    }
    // 记录一个字节
    private void record(int b) throws IOException{
        if(this.position>=this.buffer.length){
            this.diskStream.write((byte)b);
        }else{
            buffer[(int)position]=(byte)b;
        }
        this.position++;
    }
    // 记录多个字节
    private void record(byte[] b,int off,int len) throws IOException{
        if(position>=this.buffer.length){   // 如果缓存已经满了,则写入硬盘
            if(this.diskStream==null){
                throw new IOException("diskStream is null for ".concat(Thread.currentThread().getName()));
            }
            this.diskStream.write(b, off, len); // 写入硬盘
            this.position+=len; // 位置增加
        }else{  // 没满,则写入缓存.如果此时缓存写满了,则再写入磁盘
            int toCopy=Math.min(this.buffer.length-(int)this.position, len);    // 计算要写入缓存的长度,不让缓存爆掉
            System.arraycopy(b, off, this.buffer, (int)this.position, len);     // 拷贝到缓存
            this.position+=toCopy;
            
            if(toCopy<len){ // 如果缓存已满,则将剩下的数据写入硬盘
                //this.diskStream.write(b,off+toCopy,len-toCopy);     
                record(b,off+toCopy,len-toCopy);    // 为什么不直接用上一行代码?需要验证diskStream
            }
        }
    }
    // 写入数据
    @Override
    public void write(int b) throws IOException {
        if(recording){
            record(b);
        }
    }
    // 写入数据
    @Override
    public void write(byte[] b, int off, int len) throws IOException {
       if(recording){
           record(b,off,len);
       }
    }
    // 写入数据
    @Override
    public void write(byte[] b) throws IOException {
        if(recording){
            record(b,0,b.length);
        }
    }
   
    // 关闭,关闭了才能获得长度
    @Override
    public void close() throws IOException {
        isOpen=false;
        closeRecorder();
    }
    
    
   
    // 刷新
    @Override
    public void flush() throws IOException {
       if(this.diskStream!=null){
           this.diskStream.flush();
       }
    }
    // 获得数据大小
    public long getSize() {
        return size;
    }
    
    public static void main(String[] args) {
        String dir=new File("").getAbsolutePath().concat(File.separator);
        String fileMemory=dir.concat("fileMemory.txt");
        String fileDisk=dir.concat("fileDisk.txt");
        int bufferSize=5;
        MyOutputStream mosMemory=null;
        MyOutputStream mosDisk=null;
        try {
            mosMemory=new MyOutputStream(bufferSize,fileMemory);
            mosMemory.open();
            
            mosDisk=new MyOutputStream(bufferSize,fileDisk);
            mosDisk.open();
            
            for(int i=0;i<100;i++){
                if(i<bufferSize){
                    mosMemory.write(i);
                }
                mosDisk.write(i);
            }
            
            mosMemory.close();
            mosDisk.close();
            
            System.out.println("mosMemory length:"+mosMemory.getSize());
            System.out.println("mosDisk length:"+mosDisk.getSize());
            
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally{
            
        }
    }

}



更多技术文章、感悟、分享、勾搭,请用微信扫描:

分享到:
评论

相关推荐

    Java输入输出流以及线程讲解

    Java输入输出流(I/O流)是Java编程中不可或缺的一部分,它允许程序处理数据的读取、写入和传输。Java I/O系统基于流的概念,流可以被视为数据的有序序列,既可以是从源(如文件、网络连接)读取数据的输入流,也...

    IO和线程java输入输出 多线程

    输入/输出处理数据的传输,而多线程则涉及程序的并发执行。 首先,让我们深入理解Java的IO系统。Java.IO包包含了大量用于处理输入和输出操作的类和接口。输入流(InputStream)和输出流(OutputStream)是这个包的...

    JAVA输入输出流实验报告

    Java中的输入输出流是程序与外部数据...总之,Java的输入输出流是其强大的特性之一,为开发者提供了灵活且高效的处理数据输入输出的能力。通过不断的实践和学习,我们可以掌握更多的IO技巧,更好地应对各种实际问题。

    java实现多线程文件传输

    5. **I/O流**:在Java中,`InputStream`和`OutputStream`是用于读写文件的基础类,多线程传输时,每个线程可以拥有自己的输入/输出流实例,分别处理文件的一部分。 6. **异常处理**:多线程环境下,需要确保每个...

    java输入输出流,电子课件

    Java输入输出流是Java编程中不可或缺的部分,它用于应用程序与外部设备之间进行数据交换,比如磁盘、网络、键盘和显示器。I/O流是Java中处理输入和输出的基础框架,它提供了一种抽象的方式来处理不同类型的输入源和...

    java中的标准输入输出流

    Java提供了丰富的I/O处理机制,包括标准输入输出流、字节流、字符流等多种方式来处理数据的读取和写入。标准输入输出流是Java中非常基础且重要的组成部分。 **1.1 标准输入输出流简介** - **System.out**: 是一个`...

    java多线程URL方式下载单个大文件

    然后,我们引入`java.nio`包,这个包提供了非阻塞I/O操作,使得在多线程环境下处理数据更高效。特别是`java.nio.channels.Channels`和`java.nio.file.Files`类,它们可以帮助我们将输入流转换为通道,并将数据写入到...

    java多线程文件传输(基于swing)

    Java多线程文件传输是一个复杂而实用的编程概念,它结合了Java的Socket编程和Swing GUI库,用于实现高效的数据交换。在这个项目中,开发者创建了一个基于Socket的多线程文件传输系统,允许用户通过图形化用户界面...

    文件管理和输入输出流.rar

    "文件管理和输入输出流"这个主题涵盖了Java、C语言、C++、C#以及JSP等多种编程语言中的相关技术,这些技术使得程序员能够有效地读取、写入和处理文件数据。 首先,我们来探讨文件管理。文件管理主要包括创建、打开...

    java输入输出流的两种写法

    Java 输入输出流是Java编程语言中处理数据传输的基础机制,主要负责程序与外部资源(如文件、网络连接等)之间的数据交互。Java 提供了多种类型的流,它们分为两大类:字节流(处理单个字节的数据)和字符流(处理...

    java基础代码_java_输入输出流_接口_多线程_异常_

    在Java中,输入输出流是一组类和接口,用于读取和写入数据到不同的源和目标,如文件、网络连接或内存。Java的IO流分为字节流和字符流两大类,字节流处理原始的8位字节数据,而字符流则处理Unicode字符。基本的输入流...

    java输入输出流的代码示例

    Java输入输出流是Java编程语言中的核心概念,用于在程序之间、程序与文件系统、网络连接等不同数据源之间传输数据。在这个主题中,我们将深入探讨Java输入输出流的使用,通过具体的代码示例帮助你理解和掌握这个关键...

    java多线程下载工具,仿照迅雷

    3. **输入/输出流**:Java的IO流是处理数据输入和输出的基础,下载工具中通常会用到`InputStream`(用于读取服务器的数据)和`OutputStream`(用于将数据写入本地文件)。例如,我们可以使用`BufferedInputStream`和...

    Java语言与面向对象程序设计第16讲(异常处理,多线程和流式输入输出与文件处理)

    总的来说,Java的异常处理、多线程和流式输入输出与文件处理是编程中重要的概念,理解并熟练运用它们能帮助开发者编写更健壮、安全和高效的代码。对于初学者而言,通过阅读详细的教程和实践练习,可以逐步掌握这些...

    Java学习资料(内含基本语法、异常处理、Applet编程、GUI、线程、输入输出流等)

    综上所述,这份Java学习资料涵盖了从基础到高级的多个主题,包括基本语法、面向对象编程、异常处理、Applet、GUI设计、多线程以及输入输出流。对于想要系统学习Java的初学者,这是一份非常全面且深入的学习资源。...

    java多线程网络传输文件(非同步)

    ### Java多线程网络传输文件(非同步) #### 概述 在现代软件开发中,尤其是在涉及大量数据传输的应用场景下,高效的文件传输方案尤为重要。Java作为一种广泛应用的编程语言,提供了丰富的工具和技术来实现高性能...

    Java输入输出流

    ### Java输入输出流详解 #### 一、Java IO 概述 在计算机程序设计中,输入输出(Input/Output,简称IO)是非常重要的一个概念。它涉及到程序如何与外部世界进行数据交换,最常见的外部设备包括磁盘存储和网络通信等...

    WHUT-java多线程实验-第三周-文件上传和下载.zip

    总的来说,这个实验将教会你如何在Java多线程环境中实现高效、稳定的文件上传和下载功能,这是一项对任何开发人员来说都非常实用的技能,尤其是在构建高性能的Web应用或后台服务时。通过实践和理解这些概念,你将...

    java多线程下载源代码

    Java多线程下载是利用Java编程语言实现的一种高效下载大文件的技术。在传统的单线程下载方式中,如果网络环境不稳定或文件较大,下载过程可能会很慢,甚至中断。而多线程下载则是将文件分割成多个部分,每个部分由一...

    输入输出流及线程资料

    在Java编程语言中,输入输出流(Input/Output Stream)是处理数据传输的核心概念,而线程则是实现并发处理和程序高效运行的关键机制。这两者在构建高效、响应迅速的应用程序时都扮演着至关重要的角色。 输入输出流...

Global site tag (gtag.js) - Google Analytics