FTP(File Transfer Protocol)를 활용해서 파일 업로드 및 다운로드 예제를 정리하려고 합니다.         1. FTP 사전 준비 AndroidManifest 권한 추가  (파일 읽고/쓰기 권한은 MainActivity 에서도 따로...

[안드로이드] 코틀린 FTP 파일 전송 (업로드/다운로드)

FTP(File Transfer Protocol)를 활용해서 파일 업로드 및 다운로드 예제를 정리하려고 합니다.



 

 

 

 

1. FTP 사전 준비

AndroidManifest 권한 추가 

(파일 읽고/쓰기 권한은 MainActivity 에서도 따로 권한 요청을 해주시기 바랍니다.)

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

<application
android:requestLegacyExternalStorage="true"

...
</application>

 

Gradle 라이브러리 추가

implementation("commons-net:commons-net:3.6")

 

 

 

 

 

 

 

2. FTPUtil 클래스

FTPUtil 이름을 가진 object class를 생성하였습니다.

코틀린 코루틴을 활용하여 파일 업로드 및 다운로드 동작을 구현하였습니다.

 

사용하실 때 FTP 설정을 빠트리면 안됩니다! (경험담..)

 

object FTPUtil {
private val coroutineScope = CoroutineScope(Dispatchers.Default)

private var clientFTP = FTPClient()

// Input your default setting
private var host = ""
private var user = ""
private var password = ""
private var port = 21

fun changeFTPSetting(host: String, user: String, password: String, port: Int) {
this.host = host
this.user = user
this.password = password
this.port = port
}

suspend fun downloadFile(srcFilePath: String, desFilePath: String): Boolean {
return coroutineScope.async {
var result = false
try {
if (connect()) {
val fileOutputStream = FileOutputStream(desFilePath)
result = clientFTP.retrieveFile(srcFilePath, fileOutputStream)
fileOutputStream.close()
}
} catch (e: Exception) {
println("[FTPUtil] e $e")
e.printStackTrace()
}

disconnect()

println("[FTPUtil] downloadFile result : $result")

result
}.await()
}

suspend fun uploadFile(srcFilePath: String, desFileName: String, desDirectory: String): Boolean {
return coroutineScope.async {
var result = false
try {
if (connect()) {
val fileInputStream = FileInputStream(srcFilePath)
if (changeDirectory(desDirectory)) {
result = clientFTP.storeFile(desFileName, fileInputStream)
}
fileInputStream.close()
}
} catch (e: Exception) {
println("[FTPUtil] e $e")
e.printStackTrace()
}

disconnect()

println("[FTPUtil] uploadFile $result")

result
}.await()
}

suspend fun getFiles(directory: String): ArrayList<FTPFile> {
return coroutineScope.async {
val fileList = ArrayList<FTPFile>()
try {
if (connect()) {
val ftpFiles = clientFTP.listFiles(directory)
for (file in ftpFiles) fileList.add(file)
}
} catch (e: Exception) {
println("[FTPUtil] e $e")
e.printStackTrace()
}

disconnect()

println("[FTPUtil] getFiles size ${fileList.size}")

fileList
}.await()
}

private fun connect(): Boolean {
clientFTP.controlEncoding = "euc-kr"
clientFTP.connect(host, port)
if (!FTPReply.isPositiveCompletion(clientFTP.replyCode)) {
println("[FTPUtil] $host, $port connect fail")
return false
}

if (!clientFTP.login(user, password)) {
println("[FTPUtil] $user, $password login fail")
return false
}

clientFTP.enterLocalPassiveMode()

println("[FTPUtil] FTP connected : host($host), user($user), password($password), port($port)")

return true
}

private fun disconnect(): Boolean {
try {
clientFTP.logout()
clientFTP.disconnect()
} catch (e: Exception) {
e.printStackTrace()
println("[FTPUtil] e $e")
}

return true
}

private fun changeDirectory(directory: String): Boolean {
try {
clientFTP.changeWorkingDirectory(directory)
return true
} catch (e: Exception) {
e.printStackTrace()
println("[FTPUtil] e $e")
}
return false
}

private fun getCurrentDirectory(): String {
return try {
clientFTP.printWorkingDirectory()
} catch (e: Exception) {
""
}
}
}

 

 

 

 

 

 

 

3. FTP 업로드 / 다운로드 사용 예시

Upload, Download, GetFiles 버튼을 생성하여 아래와 같이 동작시켜 확인할 수 있었습니다. 

 

class MainActivity : AppCompatActivity() {

private lateinit var binding: ActivityMainBinding

private val coroutineScope = CoroutineScope(Dispatchers.Default)

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)

permissionCheck()

binding.btnUpload.setOnClickListener {
coroutineScope.launch {
val srcFilePath = "sdcard/Download/test.txt"
val desFileName = "test.txt"
val desDirectory = "/user/tempDir"
FTPUtil.uploadFile(srcFilePath, desFileName, desDirectory)
}
}

binding.btnDownload.setOnClickListener {
coroutineScope.launch {
val srcFilePath = "/user/tempDir/test.txt"
val desFilePath = "sdcard/Download/test.txt"
FTPUtil.downloadFile(srcFilePath, desFilePath)
}
}

binding.btnGetFiles.setOnClickListener {
coroutineScope.launch {
val directory = "/user/tempDir"
val files = FTPUtil.getFiles(directory)
for (file in files) {
println("getFiles : ${file.name}")
}
}
}
}

...

 

 

 

 

0 comments: