热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Android中FTP上传、下载的功能实现(含进度)

 Android中使用的FTP上传、下载,含有进度。 代码部分主要分为三个文件:MainActivity,FTP,Progr

 Android中使用的FTP上传、下载,含有进度。

代码部分主要分为三个文件:MainActivity,FTP,ProgressInputStream

1. MainActivity

package com.ftp; 
 
import java.io.File; 
import java.io.IOException; 
import java.util.LinkedList; 
 
import com.ftp.FTP.DeleteFileProgressListener; 
import com.ftp.FTP.DownLoadProgressListener; 
import com.ftp.FTP.UploadProgressListener; 
 
import android.app.Activity; 
import android.os.Bundle; 
import android.os.Message; 
import android.util.Log; 
import android.view.View; 
import android.view.View.OnClickListener; 
import android.widget.Button; 
import android.widget.EditText; 
import android.widget.Toast; 
 
public class MainActivity extends Activity { 
 
  private static final String TAG = "MainActivity"; 
   
  public static final String FTP_CONNECT_SUCCESSS = "ftp连接成功"; 
  public static final String FTP_CONNECT_FAIL = "ftp连接失败"; 
  public static final String FTP_DISCONNECT_SUCCESS = "ftp断开连接"; 
  public static final String FTP_FILE_NOTEXISTS = "ftp上文件不存在"; 
   
  public static final String FTP_UPLOAD_SUCCESS = "ftp文件上传成功"; 
  public static final String FTP_UPLOAD_FAIL = "ftp文件上传失败"; 
  public static final String FTP_UPLOAD_LOADING = "ftp文件正在上传"; 
 
  public static final String FTP_DOWN_LOADING = "ftp文件正在下载"; 
  public static final String FTP_DOWN_SUCCESS = "ftp文件下载成功"; 
  public static final String FTP_DOWN_FAIL = "ftp文件下载失败"; 
   
  public static final String FTP_DELETEFILE_SUCCESS = "ftp文件删除成功"; 
  public static final String FTP_DELETEFILE_FAIL = "ftp文件删除失败"; 
 
  @Override 
  protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 
     
    initView(); 
  } 
 
  private void initView() { 
     
    //上传功能 
    //new FTP().uploadMultiFile为多文件上传 
    //new FTP().uploadSingleFile为单文件上传 
    Button buttOnUpload= (Button) findViewById(R.id.button_upload);     
    buttonUpload.setOnClickListener(new OnClickListener() {       
      @Override 
      public void onClick(View v) { 
 
          new Thread(new Runnable() {      
            @Override 
            public void run() { 
               
              // 上传 
              File file = new File("/mnt/sdcard/ftpTest.docx"); 
              try { 
                 
                //单文件上传 
                new FTP().uploadSingleFile(file, "/fff",new UploadProgressListener(){ 
 
                  @Override 
                  public void onUploadProgress(String currentStep,long uploadSize,File file) { 
                    // TODO Auto-generated method stub 
                    Log.d(TAG, currentStep);                     
                    if(currentStep.equals(MainActivity.FTP_UPLOAD_SUCCESS)){ 
                      Log.d(TAG, "-----shanchuan--successful"); 
                    } else if(currentStep.equals(MainActivity.FTP_UPLOAD_LOADING)){ 
                      long fize = file.length(); 
                      float num = (float)uploadSize / (float)fize; 
                      int result = (int)(num * 100); 
                      Log.d(TAG, "-----shangchuan---"+result + "%"); 
                    } 
                  }               
                }); 
              } catch (IOException e) { 
                // TODO Auto-generated catch block 
                e.printStackTrace(); 
              } 
               
            } 
          }).start(); 
            
      } 
    }); 
   
    //下载功能 
    Button buttOnDown= (Button)findViewById(R.id.button_down); 
    buttonDown.setOnClickListener(new View.OnClickListener() {      
      @Override 
      public void onClick(View v) { 
         
        new Thread(new Runnable() {      
          @Override 
          public void run() { 
             
            // 下载 
            try { 
               
              //单文件下载 
              new FTP().downloadSingleFile("/fff/ftpTest.docx","/mnt/sdcard/download/","ftpTest.docx",new DownLoadProgressListener(){ 
 
                @Override 
                public void onDownLoadProgress(String currentStep, long downProcess, File file) { 
                  Log.d(TAG, currentStep);                     
                  if(currentStep.equals(MainActivity.FTP_DOWN_SUCCESS)){ 
                    Log.d(TAG, "-----xiazai--successful"); 
                  } else if(currentStep.equals(MainActivity.FTP_DOWN_LOADING)){ 
                    Log.d(TAG, "-----xiazai---"+downProcess + "%"); 
                  } 
                } 
                 
              });              
             
            } catch (Exception e) { 
              // TODO Auto-generated catch block 
              e.printStackTrace(); 
            } 
             
          } 
        }).start(); 
         
      } 
    }); 
   
    //删除功能 
    Button buttOnDelete= (Button)findViewById(R.id.button_delete); 
    buttonDelete.setOnClickListener(new View.OnClickListener() {       
      @Override 
      public void onClick(View v) { 
         
        new Thread(new Runnable() {      
          @Override 
          public void run() { 
             
            // 删除 
            try { 
 
              new FTP().deleteSingleFile("/fff/ftpTest.docx",new DeleteFileProgressListener(){ 
 
                @Override 
                public void onDeleteProgress(String currentStep) { 
                  Log.d(TAG, currentStep);                     
                  if(currentStep.equals(MainActivity.FTP_DELETEFILE_SUCCESS)){ 
                    Log.d(TAG, "-----shanchu--success"); 
                  } else if(currentStep.equals(MainActivity.FTP_DELETEFILE_FAIL)){ 
                    Log.d(TAG, "-----shanchu--fail"); 
                  } 
                } 
                 
              });              
             
            } catch (Exception e) { 
              // TODO Auto-generated catch block 
              e.printStackTrace(); 
            } 
             
          } 
        }).start(); 
         
      } 
    }); 
   
  } 
} 

2. FTP

package com.ftp; 
 
import java.io.BufferedInputStream; 
import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.OutputStream; 
import java.util.Date; 
import java.util.LinkedList; 
import org.apache.commons.net.ftp.FTPClient; 
import org.apache.commons.net.ftp.FTPClientConfig; 
import org.apache.commons.net.ftp.FTPFile; 
import org.apache.commons.net.ftp.FTPReply; 
 
public class FTP { 
  /** 
   * 服务器名. 
   */ 
  private String hostName; 
 
  /** 
   * 端口号 
   */ 
  private int serverPort; 
 
  /** 
   * 用户名. 
   */ 
  private String userName; 
 
  /** 
   * 密码. 
   */ 
  private String password; 
 
  /** 
   * FTP连接. 
   */ 
  private FTPClient ftpClient; 
 
  public FTP() { 
    this.hostName = "192.168.1.101"; 
    this.serverPort = 21; 
    this.userName = "admin"; 
    this.password = "1234"; 
    this.ftpClient = new FTPClient(); 
  } 
 
  // -------------------------------------------------------文件上传方法------------------------------------------------ 
 
  /** 
   * 上传单个文件. 
   * 
   * @param localFile 
   *      本地文件 
   * @param remotePath 
   *      FTP目录 
   * @param listener 
   *      监听器 
   * @throws IOException 
   */ 
  public void uploadSingleFile(File singleFile, String remotePath, 
      UploadProgressListener listener) throws IOException { 
 
    // 上传之前初始化 
    this.uploadBeforeOperate(remotePath, listener); 
 
    boolean flag; 
    flag = uploadingSingle(singleFile, listener); 
    if (flag) { 
      listener.onUploadProgress(MainActivity.FTP_UPLOAD_SUCCESS, 0, 
          singleFile); 
    } else { 
      listener.onUploadProgress(MainActivity.FTP_UPLOAD_FAIL, 0, 
          singleFile); 
    } 
 
    // 上传完成之后关闭连接 
    this.uploadAfterOperate(listener); 
  } 
 
  /** 
   * 上传多个文件. 
   * 
   * @param localFile 
   *      本地文件 
   * @param remotePath 
   *      FTP目录 
   * @param listener 
   *      监听器 
   * @throws IOException 
   */ 
  public void uploadMultiFile(LinkedList fileList, String remotePath, 
      UploadProgressListener listener) throws IOException { 
 
    // 上传之前初始化 
    this.uploadBeforeOperate(remotePath, listener); 
 
    boolean flag; 
 
    for (File singleFile : fileList) { 
      flag = uploadingSingle(singleFile, listener); 
      if (flag) { 
        listener.onUploadProgress(MainActivity.FTP_UPLOAD_SUCCESS, 0, 
            singleFile); 
      } else { 
        listener.onUploadProgress(MainActivity.FTP_UPLOAD_FAIL, 0, 
            singleFile); 
      } 
    } 
 
    // 上传完成之后关闭连接 
    this.uploadAfterOperate(listener); 
  } 
 
  /** 
   * 上传单个文件. 
   * 
   * @param localFile 
   *      本地文件 
   * @return true上传成功, false上传失败 
   * @throws IOException 
   */ 
  private boolean uploadingSingle(File localFile, 
      UploadProgressListener listener) throws IOException { 
    boolean flag = true; 
    // 不带进度的方式 
    // // 创建输入流 
    // InputStream inputStream = new FileInputStream(localFile); 
    // // 上传单个文件 
    // flag = ftpClient.storeFile(localFile.getName(), inputStream); 
    // // 关闭文件流 
    // inputStream.close(); 
 
    // 带有进度的方式 
    BufferedInputStream buffIn = new BufferedInputStream( 
        new FileInputStream(localFile)); 
    ProgressInputStream progressInput = new ProgressInputStream(buffIn, 
        listener, localFile); 
    flag = ftpClient.storeFile(localFile.getName(), progressInput); 
    buffIn.close(); 
 
    return flag; 
  } 
   
  /** 
   * 上传文件之前初始化相关参数 
   * 
   * @param remotePath 
   *      FTP目录 
   * @param listener 
   *      监听器 
   * @throws IOException 
   */ 
  private void uploadBeforeOperate(String remotePath, 
      UploadProgressListener listener) throws IOException { 
 
    // 打开FTP服务 
    try { 
      this.openConnect(); 
      listener.onUploadProgress(MainActivity.FTP_CONNECT_SUCCESSS, 0, 
          null); 
    } catch (IOException e1) { 
      e1.printStackTrace(); 
      listener.onUploadProgress(MainActivity.FTP_CONNECT_FAIL, 0, null); 
      return; 
    } 
 
    // 设置模式 
    ftpClient.setFileTransferMode(org.apache.commons.net.ftp.FTP.STREAM_TRANSFER_MODE); 
    // FTP下创建文件夹 
    ftpClient.makeDirectory(remotePath); 
    // 改变FTP目录 
    ftpClient.changeWorkingDirectory(remotePath); 
    // 上传单个文件 
 
  } 
 
  /** 
   * 上传完成之后关闭连接 
   * 
   * @param listener 
   * @throws IOException 
   */ 
  private void uploadAfterOperate(UploadProgressListener listener) 
      throws IOException { 
    this.closeConnect(); 
    listener.onUploadProgress(MainActivity.FTP_DISCONNECT_SUCCESS, 0, null); 
  } 
 
  // -------------------------------------------------------文件下载方法------------------------------------------------ 
 
  /** 
   * 下载单个文件,可实现断点下载. 
   * 
   * @param serverPath 
   *      Ftp目录及文件路径 
   * @param localPath 
   *      本地目录 
   * @param fileName    
   *      下载之后的文件名称 
   * @param listener 
   *      监听器 
   * @throws IOException 
   */ 
  public void downloadSingleFile(String serverPath, String localPath, String fileName, DownLoadProgressListener listener) 
      throws Exception { 
 
    // 打开FTP服务 
    try { 
      this.openConnect(); 
      listener.onDownLoadProgress(MainActivity.FTP_CONNECT_SUCCESSS, 0, null); 
    } catch (IOException e1) { 
      e1.printStackTrace(); 
      listener.onDownLoadProgress(MainActivity.FTP_CONNECT_FAIL, 0, null); 
      return; 
    } 
 
    // 先判断服务器文件是否存在 
    FTPFile[] files = ftpClient.listFiles(serverPath); 
    if (files.length == 0) { 
      listener.onDownLoadProgress(MainActivity.FTP_FILE_NOTEXISTS, 0, null); 
      return; 
    } 
 
    //创建本地文件夹 
    File mkFile = new File(localPath); 
    if (!mkFile.exists()) { 
      mkFile.mkdirs(); 
    } 
 
    localPath = localPath + fileName; 
    // 接着判断下载的文件是否能断点下载 
    long serverSize = files[0].getSize(); // 获取远程文件的长度 
    File localFile = new File(localPath); 
    long localSize = 0; 
    if (localFile.exists()) { 
      localSize = localFile.length(); // 如果本地文件存在,获取本地文件的长度 
      if (localSize >= serverSize) { 
        File file = new File(localPath); 
        file.delete(); 
      } 
    } 
     
    // 进度 
    long step = serverSize / 100; 
    long process = 0; 
    long currentSize = 0; 
    // 开始准备下载文件 
    OutputStream out = new FileOutputStream(localFile, true); 
    ftpClient.setRestartOffset(localSize); 
    InputStream input = ftpClient.retrieveFileStream(serverPath); 
    byte[] b = new byte[1024]; 
    int length = 0; 
    while ((length = input.read(b)) != -1) { 
      out.write(b, 0, length); 
      currentSize = currentSize + length; 
      if (currentSize / step != process) { 
        process = currentSize / step; 
        if (process % 5 == 0) { //每隔%5的进度返回一次 
          listener.onDownLoadProgress(MainActivity.FTP_DOWN_LOADING, process, null); 
        } 
      } 
    } 
    out.flush(); 
    out.close(); 
    input.close(); 
     
    // 此方法是来确保流处理完毕,如果没有此方法,可能会造成现程序死掉 
    if (ftpClient.completePendingCommand()) { 
      listener.onDownLoadProgress(MainActivity.FTP_DOWN_SUCCESS, 0, new File(localPath)); 
    } else { 
      listener.onDownLoadProgress(MainActivity.FTP_DOWN_FAIL, 0, null); 
    } 
 
    // 下载完成之后关闭连接 
    this.closeConnect(); 
    listener.onDownLoadProgress(MainActivity.FTP_DISCONNECT_SUCCESS, 0, null); 
 
    return; 
  } 
 
  // -------------------------------------------------------文件删除方法------------------------------------------------ 
 
  /** 
   * 删除Ftp下的文件. 
   * 
   * @param serverPath 
   *      Ftp目录及文件路径 
   * @param listener 
   *      监听器 
   * @throws IOException 
   */ 
  public void deleteSingleFile(String serverPath, DeleteFileProgressListener listener) 
      throws Exception { 
 
    // 打开FTP服务 
    try { 
      this.openConnect(); 
      listener.onDeleteProgress(MainActivity.FTP_CONNECT_SUCCESSS); 
    } catch (IOException e1) { 
      e1.printStackTrace(); 
      listener.onDeleteProgress(MainActivity.FTP_CONNECT_FAIL); 
      return; 
    } 
 
    // 先判断服务器文件是否存在 
    FTPFile[] files = ftpClient.listFiles(serverPath); 
    if (files.length == 0) { 
      listener.onDeleteProgress(MainActivity.FTP_FILE_NOTEXISTS); 
      return; 
    } 
     
    //进行删除操作 
    boolean flag = true; 
    flag = ftpClient.deleteFile(serverPath); 
    if (flag) { 
      listener.onDeleteProgress(MainActivity.FTP_DELETEFILE_SUCCESS); 
    } else { 
      listener.onDeleteProgress(MainActivity.FTP_DELETEFILE_FAIL); 
    } 
     
    // 删除完成之后关闭连接 
    this.closeConnect(); 
    listener.onDeleteProgress(MainActivity.FTP_DISCONNECT_SUCCESS); 
     
    return; 
  } 
 
  // -------------------------------------------------------打开关闭连接------------------------------------------------ 
 
  /** 
   * 打开FTP服务. 
   * 
   * @throws IOException 
   */ 
  public void openConnect() throws IOException { 
    // 中文转码 
    ftpClient.setControlEncoding("UTF-8"); 
    int reply; // 服务器响应值 
    // 连接至服务器 
    ftpClient.connect(hostName, serverPort); 
    // 获取响应值 
    reply = ftpClient.getReplyCode(); 
    if (!FTPReply.isPositiveCompletion(reply)) { 
      // 断开连接 
      ftpClient.disconnect(); 
      throw new IOException("connect fail: " + reply); 
    } 
    // 登录到服务器 
    ftpClient.login(userName, password); 
    // 获取响应值 
    reply = ftpClient.getReplyCode(); 
    if (!FTPReply.isPositiveCompletion(reply)) { 
      // 断开连接 
      ftpClient.disconnect(); 
      throw new IOException("connect fail: " + reply); 
    } else { 
      // 获取登录信息 
      FTPClientConfig cOnfig= new FTPClientConfig(ftpClient 
          .getSystemType().split(" ")[0]); 
      config.setServerLanguageCode("zh"); 
      ftpClient.configure(config); 
      // 使用被动模式设为默认 
      ftpClient.enterLocalPassiveMode(); 
      // 二进制文件支持 
      ftpClient 
          .setFileType(org.apache.commons.net.ftp.FTP.BINARY_FILE_TYPE); 
    } 
  } 
 
  /** 
   * 关闭FTP服务. 
   * 
   * @throws IOException 
   */ 
  public void closeConnect() throws IOException { 
    if (ftpClient != null) { 
      // 退出FTP 
      ftpClient.logout(); 
      // 断开连接 
      ftpClient.disconnect(); 
    } 
  } 
 
  // ---------------------------------------------------上传、下载、删除监听--------------------------------------------- 
   
  /* 
   * 上传进度监听 
   */ 
  public interface UploadProgressListener { 
    public void onUploadProgress(String currentStep, long uploadSize, File file); 
  } 
 
  /* 
   * 下载进度监听 
   */ 
  public interface DownLoadProgressListener { 
    public void onDownLoadProgress(String currentStep, long downProcess, File file); 
  } 
 
  /* 
   * 文件删除监听 
   */ 
  public interface DeleteFileProgressListener { 
    public void onDeleteProgress(String currentStep); 
  } 
 
} 

3. ProgressInputStream

package com.ftp; 
 
import java.io.File; 
import java.io.IOException; 
import java.io.InputStream; 
 
import com.ftp.FTP.UploadProgressListener; 
 
import android.os.Bundle; 
import android.os.Handler; 
import android.os.Message; 
import android.util.Log; 
 
public class ProgressInputStream extends InputStream { 
 
  private static final int TEN_KILOBYTES = 1024 * 10; //每上传10K返回一次 
 
  private InputStream inputStream; 
 
  private long progress; 
  private long lastUpdate; 
 
  private boolean closed; 
   
  private UploadProgressListener listener; 
  private File localFile; 
 
  public ProgressInputStream(InputStream inputStream,UploadProgressListener listener,File localFile) { 
    this.inputStream = inputStream; 
    this.progress = 0; 
    this.lastUpdate = 0; 
    this.listener = listener; 
    this.localFile = localFile; 
     
    this.closed = false; 
  } 
 
  @Override 
  public int read() throws IOException { 
    int count = inputStream.read(); 
    return incrementCounterAndUpdateDisplay(count); 
  } 
 
  @Override 
  public int read(byte[] b, int off, int len) throws IOException { 
    int count = inputStream.read(b, off, len); 
    return incrementCounterAndUpdateDisplay(count); 
  } 
 
  @Override 
  public void close() throws IOException { 
    super.close(); 
    if (closed) 
      throw new IOException("already closed"); 
    closed = true; 
  } 
 
  private int incrementCounterAndUpdateDisplay(int count) { 
    if (count > 0) 
      progress += count; 
    lastUpdate = maybeUpdateDisplay(progress, lastUpdate); 
    return count; 
  } 
 
  private long maybeUpdateDisplay(long progress, long lastUpdate) { 
    if (progress - lastUpdate > TEN_KILOBYTES) { 
      lastUpdate = progress; 
      this.listener.onUploadProgress(MainActivity.FTP_UPLOAD_LOADING, progress, this.localFile); 
    } 
    return lastUpdate; 
  } 
   
  
   
} 

原文链接:http://blog.csdn.net/tianyitianyi1/article/details/38637999

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • mac php错误日志配置方法及错误级别修改
    本文介绍了在mac环境下配置php错误日志的方法,包括修改php.ini文件和httpd.conf文件的操作步骤。同时还介绍了如何修改错误级别,以及相应的错误级别参考链接。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 一句话解决高并发的核心原则
    本文介绍了解决高并发的核心原则,即将用户访问请求尽量往前推,避免访问CDN、静态服务器、动态服务器、数据库和存储,从而实现高性能、高并发、高可扩展的网站架构。同时提到了Google的成功案例,以及适用于千万级别PV站和亿级PV网站的架构层次。 ... [详细]
  • Android日历提醒软件开源项目分享及使用教程
    本文介绍了一款名为Android日历提醒软件的开源项目,作者分享了该项目的代码和使用教程,并提供了GitHub项目地址。文章详细介绍了该软件的主界面风格、日程信息的分类查看功能,以及添加日程提醒和查看详情的界面。同时,作者还提醒了读者在使用过程中可能遇到的Android6.0权限问题,并提供了解决方法。 ... [详细]
  • 一、Hadoop来历Hadoop的思想来源于Google在做搜索引擎的时候出现一个很大的问题就是这么多网页我如何才能以最快的速度来搜索到,由于这个问题Google发明 ... [详细]
  • 拥抱Android Design Support Library新变化(导航视图、悬浮ActionBar)
    转载请注明明桑AndroidAndroid5.0Loollipop作为Android最重要的版本之一,为我们带来了全新的界面风格和设计语言。看起来很受欢迎࿰ ... [详细]
  • 本文介绍了通过ABAP开发往外网发邮件的需求,并提供了配置和代码整理的资料。其中包括了配置SAP邮件服务器的步骤和ABAP写发送邮件代码的过程。通过RZ10配置参数和icm/server_port_1的设定,可以实现向Sap User和外部邮件发送邮件的功能。希望对需要的开发人员有帮助。摘要长度:184字。 ... [详细]
  • Android系统移植与调试之如何修改Android设备状态条上音量加减键在横竖屏切换的时候的显示于隐藏
    本文介绍了如何修改Android设备状态条上音量加减键在横竖屏切换时的显示与隐藏。通过修改系统文件system_bar.xml实现了该功能,并分享了解决思路和经验。 ... [详细]
  • 本文介绍了在Linux下安装和配置Kafka的方法,包括安装JDK、下载和解压Kafka、配置Kafka的参数,以及配置Kafka的日志目录、服务器IP和日志存放路径等。同时还提供了单机配置部署的方法和zookeeper地址和端口的配置。通过实操成功的案例,帮助读者快速完成Kafka的安装和配置。 ... [详细]
  • 如何提高PHP编程技能及推荐高级教程
    本文介绍了如何提高PHP编程技能的方法,推荐了一些高级教程。学习任何一种编程语言都需要长期的坚持和不懈的努力,本文提醒读者要有足够的耐心和时间投入。通过实践操作学习,可以更好地理解和掌握PHP语言的特异性,特别是单引号和双引号的用法。同时,本文也指出了只走马观花看整体而不深入学习的学习方式无法真正掌握这门语言,建议读者要从整体来考虑局部,培养大局观。最后,本文提醒读者完成一个像模像样的网站需要付出更多的努力和实践。 ... [详细]
  • 大数据Hadoop生态(20)MapReduce框架原理OutputFormat的开发笔记
    本文介绍了大数据Hadoop生态(20)MapReduce框架原理OutputFormat的开发笔记,包括outputFormat接口实现类、自定义outputFormat步骤和案例。案例中将包含nty的日志输出到nty.log文件,其他日志输出到other.log文件。同时提供了一些相关网址供参考。 ... [详细]
  • PHP组合工具以及开发所需的工具
    本文介绍了PHP开发中常用的组合工具和开发所需的工具。对于数据分析软件,包括Excel、hihidata、SPSS、SAS、MARLAB、Eview以及各种BI与报表工具等。同时还介绍了PHP开发所需的PHP MySQL Apache集成环境,包括推荐的AppServ等版本。 ... [详细]
  • .htaccess文件 ... [详细]
  • 篇首语:本文由编程笔记#小编为大家整理,主要介绍了看大数据时代下的IT架构业界消息队列对比相关的知识,希望对你有一定的参考价值。一、MQ(MessageQue ... [详细]
  • 为什么要用Go语言做后端
    FMZ数字货币量化平台www.fmz.com,后端使用Go语言,这里是创始人Zero谈论使用G ... [详细]
author-avatar
我叫梁家耀_312
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有