Проблема в том, что иногда в полученном файле отсутствуют некоторые байты в конце.
Этого не происходит при использовании InputStream/
Код: Выделить всё
OutputStreamЭто не проблема файла: я тестировал множество разных файлов с одинаковыми результатами.
Это не проблема сервера: Я тестировал на двух разных - одинаковые результаты.
Это даже не похоже на проблему с подключением: тестировал на двух разных соединениях, одна и та же проблема.
И более того, похоже, это не проблема. проблема конкретно с Apache FTPClient: я пробовал старый ftp4j и выдает одинаково недостающие байты ближе к концу файла.
Насколько я понимаю, это InputStream.read(), который не выполняет свою работу должным образом, пропуская один байт в начале файла. конец некоторых буферов.
Код: Выделить всё
import org.apache.commons.net.ftp.FTPClient
fun downloadFile(remotePath: String, outputFile: File) {
val client = FTPClient()
client.connect("ftp.example.com")
client.login("username", "password")
client.enterLocalPassiveMode()
println(client.getSize(remotePath)) // Say 100000 bytes
//client.setFileType(FTP.BINARY_FILE_TYPE) // Doesn't matter
client.retrieveFileStream(remotePath).use { inputStream ->
outputFile.outputStream().use { outputStream ->
val buffer = ByteArray(DEFAULT_BUFFER_SIZE) // 8 * 1024
var bytes: Int
while (inputStream.read(buffer).also { bytes = it } != -1) {
outputStream.write(buffer, 0, bytes)
}
}
}
client.completePendingCommand()
client.disconnect()
println(outputFile.length()) // Usually 100000, other times 99999 or less bytes
}
Код: Выделить всё
lifecycleScope.launch(Dispatchers.IO) {
downloadFile("/path/to/input.zip", File(cacheDir, "output.zip"))
}
Очевидно, что файл большего размера и с большей вероятностью будет поврежден.< /p>
Как правильно получить двоичный файл через FTP?
Изменить
Эта проблема затрагивает только эмуляторы. Я не могу воспроизвести его на физических устройствах.
Я тестировал загрузку файла размером 300 КБ, заполненного только 012345678901234567890123456789012345678901234567890123456789...
Я добавил проверки, чтобы увидеть, есть ли какой-то байт отсутствует внутри или в конце буфера:
Код: Выделить всё
fun downloadFile(remotePath: String, outputFile: File) {
...
println("Input size: " + client.getSize(remotePath))
client.retrieveFileStream(remotePath).use { inputStream ->
outputFile.outputStream().use { outputStream ->
val buffer = ByteArray(DEFAULT_BUFFER_SIZE)
var bytes: Int
var count = 0
var lastPrev: Byte = '9'.code.toByte()
var firstNext: Byte
var prevBytes = 0
var totalBytes: Long = 0
while (inputStream.read(buffer).also { bytes = it } != -1) {
count++
firstNext = buffer[0]
checkSequence(buffer, bytes, count)
if (!checkJunction(lastPrev, firstNext))
println(
"Incoherent start of buffer $count: " +
"${lastPrev.toInt().toChar()}-${firstNext.toInt().toChar()} ($prevBytes, $bytes)"
)
lastPrev = buffer[bytes - 1]
prevBytes = bytes
totalBytes += bytes
outputStream.write(buffer, 0, bytes)
}
if (!checkJunction(lastPrev, '0'.code.toByte()))
println("Missing end of buffer $count: ${lastPrev.toInt().toChar()} ($prevBytes)")
println("Total $count buffers: $totalBytes")
}
}
client.completePendingCommand()
client.disconnect()
println("Final size: ${outputFile.length()}") // Always equal to totalBytes
}
private fun checkSequence(buffer: ByteArray, bytes: Int, count: Int) {
val nine = '9'.code.toByte()
val zero = '0'.code.toByte()
for (i in 0 until bytes - 1) {
val ok = if (buffer[i] == nine) buffer[i + 1] == zero else buffer[i + 1] == buffer[i].inc()
if (!ok) println(
"Broken buffer $count: ${buffer[i].toInt().toChar()}${buffer[i + 1].toInt().toChar()} ($i of $bytes)"
)
}
}
private fun checkJunction(lastPrev: Byte, firstNext: Byte): Boolean {
return if (lastPrev == '9'.code.toByte()) firstNext == '0'.code.toByte()
else firstNext == lastPrev.inc()
}
Размер ввода: 300000
Всего 68 буферы: 300000
Окончательный размер: 300000
Но иногда может быть что-то вроде этого:
Размер ввода: 300000
Некогерентное начало буфера 176: 8-0 (1438, 1)
Некогерентное начало буфера 179: 8-0 (1439, 1440)
Некогерентное начало буфера 181: 8-0 (2879, 1440)
Некогерентное начало буфера 184: 8-0 (1439, 1)
Разбитый буфер 185: 80 (4317 из 5758)
Несвязное начало буфера 187: 8-0 (2879, 1)
Отсутствует конец буфера 191: 8 (1439)
Всего 191 буферов: 299993
Окончательный размер: 299993
Проблема всегда заключается в том, что в конце или внутри некоторых буферов не хватает одного байта.
Затронутые буферы находятся ближе к концу входного потока.
Всегда отсутствует цифра 9, в том числе и внутри буфера.
Подробнее здесь: https://stackoverflow.com/questions/792 ... le-via-ftp
Мобильная версия