Android 使用FTP实现上传、下载等功能

Android 使用FTP实现上传、下载等功能,第1张

Android 使用FTP实现上传、下载等功能 一、前言

最近在项目中遇到使用到FTP上传和下载资源,特此记录一下实现的方式。Android实现FTP的功能主要用到了Apache的Commons Net库,将Commons Net的jar包下载引入到项目中即可。
基本使用流程图如下:

二、基本实现 2.1 连接和登录

FTP协议和HTTP协议有所不同,使用FTP进行下载时,你需要进行登录 *** 作。如果服务器没设置登录功能可忽略登录 *** 作。

    
    private fun ftpConnect(
        host: String,
        port: Int,
        username: String?,
        password: String?,
        enterLocalPassiveMode:Boolean = true
    ): FTPClient {
        val ftpClient = FTPClient()
        try {
            //设置超时时间以毫秒为单位使用时,从数据连接读。
            ftpClient.defaultTimeout = 10000
            ftpClient.connectTimeout = 10000
            ftpClient.setDataTimeout(10000)

            Log.d(TAG, "connecting to the ftp server $host:$port")
            //连接到FTP服务器
            ftpClient.connect(host, port)
            ftpClient.login(username, password)
            //是否开启被动模式
            if (enterLocalPassiveMode) {
                ftpClient.isRemoteVerificationEnabled = false
                ftpClient.enterLocalPassiveMode()
            }
            //请求使用UTF-8编码
            ftpClient.controlEncoding = "utf-8"

            val reply: Int = ftpClient.replyCode
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftpClient.disconnect()
                Log.e(TAG, "无法连接到ftp服务器,错误码为:$reply")
            } else {
                Log.d(TAG, "连接到ftp服务器")
            }
        } catch (e: Exception) {
            e.printStackTrace()
            Log.e(TAG, "Error: could not connect to host $host")
        }
        return ftpClient
    }

注意:由于FTP服务器默认的编码是ISO-8859-1,因此,客户端在获取文件信息时需要请求服务器使用UTF-8编码(如果服务器支持的话),如果服务器不支持开启UTF-8编码,那么客户端在请求remotePath路径、获取文件名时,都需要对路径进行编码转换处理。

2.2 断开连接
    
    private fun ftpDisconnect(ftpClient: FTPClient?) {
        // 判断空指针
        if (ftpClient == null) {
            return
        }
        // 断开ftp服务器连接
        try {
            ftpClient.logout()
            ftpClient.disconnect()
            Log.d(TAG, "断开连接")
        } catch (e: Exception) {
            Log.e(TAG, "Error occurred while disconnecting from ftp server.")
        }
    }

注意:在下载或上传资源时首先要连接服务器,在完成 *** 作后要记得断开连接。

2.3 上传文件
    
    fun uploadFile(
        host: String,
        port: Int,
        username: String?,
        password: String?,
        ftpSavePath: String,
        ftpSaveFileName: String,
        inputStream: InputStream
    ): Boolean {
        val ftpClient = ftpConnect(host, port, username, password)
        var flag = false
        try {
            val pathName = if (ftpSavePath.endsWith("/"))
                "$ftpSavePath$ftpSaveFileName"
            else
                "$ftpSavePath/$ftpSaveFileName"

            Log.i(
                TAG, """
                    上传文件的路径 :$pathName
                    开始上传文件...
                """.trimIndent()
            )

            //设置文件类型
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE)
            flag = ftpClient.storeFile(String(pathName.toByteArray(), Charsets.ISO_8859_1),inputStream)
            inputStream.close()
        } catch (e: Exception) {
            Log.e(TAG, e.toString())
        } finally {
            Log.i(TAG, "$ftpSaveFileName 文件上传 :" + if (flag) "成功" else "失败 ")
            try {
                inputStream.close()
            } catch (e: IOException) {
                Log.e(TAG, e.toString())
            } finally {
                ftpDisconnect(ftpClient)
            }
        }
        return flag
    }

注意:如果服务器不支持UTF-8编码,则要按上面的String(pathName.toByteArray(), Charsets.ISO_8859_1)的写法,进行编码转换处理,不然中文会乱码。如果支持UTF-8编码,则直接使用中文字符。

2.4 下载文件
    
    fun downloadFile(
        host: String,
        port: Int,
        username: String?,
        password: String?,
        pathName: String,
        localPath: String
    ): Boolean {
        val ftpClient = ftpConnect(host, port, username, password)
        var flag = false
        var outputStream: OutputStream? = null
        try {
            Log.i(
                TAG, """
                    下载文件的路径 :$pathName 
                    开始下载文件...
                    """.trimIndent()
            )
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE)


            createLocalDirectory(localPath)
            outputStream = FileOutputStream(File(localPath))
            // 下载文件
            flag = ftpClient.retrieveFile(
                String(pathName.toByteArray(), Charsets.ISO_8859_1),
                outputStream
            )
            outputStream.close()
        } catch (e: Exception) {
            Log.e(TAG, e.toString())
        } finally {
            Log.i(TAG, "$pathName 文件 :" + if (flag) "成功" else "失败 ")
            if (null != outputStream) {
                try {
                    outputStream.close()
                } catch (e: IOException) {
                    Log.e(TAG, e.toString())
                } finally {
                    ftpDisconnect(ftpClient)
                }

            }
        }
        return flag
    }

    //创建本地多层目录文件,如果已存在该文件,则不创建,如果无,则创建
    @Throws(IOException::class)
    private fun createLocalDirectory(localPath: String) {
        val path = localPath.substringBeforeLast("/")
        val file = File(path)
        if (!file.exists()) {
            file.mkdirs()
        }
    }
三、其他 *** 作

为了安全,服务器可能只给了上传和下载的权限,也有可能给了其他 *** 作权限,如删除文件、新建目录等。

3.1 创建目录
    
    @Throws(IOException::class)
    fun createDirectory(
        host: String,
        port: Int,
        username: String?,
        password: String?,
        remote: String
    ): Boolean {
        val ftpClient = ftpConnect(host, port, username, password)
        var flag = true
        val directory = remote.substring(0, remote.lastIndexOf("/") + 1)
        if (!directory.equals("/", ignoreCase = true) &&
            !ftpClient.changeWorkingDirectory(String(directory.toByteArray(), Charsets.ISO_8859_1))
        ) {
            // 如果远程目录不存在,则递归创建远程服务器目录
            var start = 0
            var end = 0
            start = if (directory.startsWith("/")) {
                1
            } else {
                0
            }
            end = directory.indexOf("/", start)
            while (true) {
                val subDirectory = String(
                    remote.substring(start, end).toByteArray(), Charsets.ISO_8859_1
                )
                if (!ftpClient.changeWorkingDirectory(subDirectory)) {
                    if (ftpClient.makeDirectory(subDirectory)) {
                        ftpClient.changeWorkingDirectory(subDirectory)
                    } else {
                        flag = false
                    }
                }
                start = end + 1
                end = directory.indexOf("/", start)

                // 检查所有目录是否创建完毕
                if (end <= start) {
                    break
                }
            }
        }
        Log.i(TAG, "$remote 文件创建 :" + if (flag) "成功" else "失败 ")
        ftpDisconnect(ftpClient)
        return flag
    }
3.2 删除文件
    
    fun deleteFile(
        host: String,
        port: Int,
        username: String?,
        password: String?,
        serverPath: String
    ): Boolean {
        val ftpClient = ftpConnect(host, port, username, password)
        val flag = deleteFile(ftpClient, serverPath)
        Log.i(TAG, "$serverPath 文件删除 :" + if (flag) "成功" else "失败 ")
        ftpDisconnect(ftpClient)
        return flag
    }

    
    private fun deleteFile(ftpClient: FTPClient, pathName: String): Boolean {
        try {
            val files = ftpClient.listFiles(pathName)
            if (files.isNotEmpty()) {
                for (file in files) {
                    if (file.isDirectory) {
                        deleteFile(ftpClient, pathName + "/" + file.name)
                        // 切换到父目录,不然删不掉文件夹
                        ftpClient.changeWorkingDirectory(
                            pathName.substring(
                                0,
                                pathName.lastIndexOf("/")
                            )
                        )
                        ftpClient.removeDirectory(pathName)
                    } else {
                        if (!ftpClient.deleteFile(pathName + "/" + file.name)) {
                            return false
                        }
                    }
                }
            }
            // 切换到父目录,不然删不掉文件夹
            ftpClient.changeWorkingDirectory(pathName.substring(0, pathName.lastIndexOf("/")))
            ftpClient.removeDirectory(pathName)
        } catch (e: IOException) {
            e.printStackTrace()
        }
        return true
    }

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/4670278.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-11-06
下一篇 2022-11-06

发表评论

登录后才能评论

评论列表(0条)

保存