Rumah > Java > javaTutorial > Kes Tepi yang Perlu Diingati. Fail Bahagian

Kes Tepi yang Perlu Diingati. Fail Bahagian

PHPz
Lepaskan: 2024-08-09 07:05:22
asal
465 orang telah melayarinya

Edge Cases to Keep in Mind. Part  Files

Tahukah anda, mungkin terdapat Fail yang wujud dan tidak wujud pada masa yang sama? Adakah anda sedar, bahawa anda boleh memadamkan fail dan masih menggunakannya? Temui kes tepi fail ini & lain-lain dalam pembangunan perisian.

Dalam artikel saya sebelum ini tentang kes tepi dalam pembangunan perisian, saya menulis tentang perangkap teks dan saya memberi anda beberapa cadangan, bagaimana untuk mengelakkannya. Dalam catatan blog ini, saya ingin menumpukan pada fail dan operasi I/O fail.

Fail yang bukan fail

API java.io.File menyediakan, antara lain, 3 kaedah ini:

  • #wujud()

  • #isDirectory()

  • #isFile()

Orang mungkin berfikir bahawa, jika ia ditunjuk oleh laluan tertentu yang wujud, objek adalah sama ada fail atau direktori — seperti dalam soalan ini pada Stack Overflow. Walau bagaimanapun, ini tidak selalunya benar.

Ia tidak disebut secara eksplisit dalam File#isFile() javadocs, tetapi fail **ada benar-benar bermaksud **fail biasa. Oleh itu, fail Unix khas seperti peranti, soket dan paip mungkin wujud tetapi ia bukan fail dalam takrifan itu.

Lihat coretan berikut:

import java.io.File

val file = File("/dev/null")
println("exists:      ${file.exists()}")
println("isFile:      ${file.isFile()}")
println("isDirectory: ${file.isDirectory()}")
Salin selepas log masuk

Seperti yang anda boleh lihat pada demo langsung, Fail yang bukan fail mahupun direktori mungkin wujud.

Wujud, atau tidak wujud?

Pautan simbolik juga merupakan fail khas tetapi ia dikendalikan secara telus hampir di mana-mana dalam API java.io (lama). Satu-satunya pengecualian ialah keluarga kaedah #getCanonicalPath()/#getCanonicalFile(). Ketelusan di sini bermakna semua operasi dimajukan kepada sasaran, sama seperti ia dilakukan secara langsung padanya. Ketelusan sedemikian biasanya berguna, mis. anda hanya boleh membaca daripada, atau menulis ke, beberapa fail. Anda tidak mengambil berat tentang resolusi laluan pautan pilihan. Walau bagaimanapun, ia juga boleh membawa kepada beberapa kes pelik. Contohnya, mungkin terdapat Fail yang wujud dan tidak wujud pada masa yang sama.

Mari kita pertimbangkan pautan simbolik yang tergantung. Sasarannya tidak wujud, jadi semua kaedah dari bahagian sebelumnya akan mengembalikan palsu. Walau bagaimanapun, laluan fail sumber masih diduduki, mis. anda tidak boleh membuat fail baharu pada laluan itu. Berikut ialah kod yang menunjukkan kes ini:

import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths

val path = Paths.get("foo")
Files.createSymbolicLink(path, path)
println("exists       : ${path.toFile().exists()}")
println("isFile       : ${path.toFile().isFile()}")
println("isDirectory  : ${path.toFile().isDirectory()}")
println("createNewFile: ${path.toFile().createNewFile()}")
Salin selepas log masuk

Dan tunjuk cara langsung.

Perintah itu penting

Dalam java.io API, untuk mencipta direktori yang mungkin tidak wujud dan memastikan ia wujud selepas itu, anda boleh menggunakan File#mkdir() (atau File#mkdirs() jika anda ingin mencipta direktori induk yang tidak wujud sebagai baik) dan kemudian File#isDirectory(). Adalah penting untuk menggunakan kaedah ini dalam susunan yang disebutkan. Mari lihat apa yang mungkin berlaku jika pesanan diterbalikkan. Dua (atau lebih) benang yang melakukan operasi yang sama diperlukan untuk menunjukkan kes ini. Di sini, kami akan menggunakan benang biru dan merah.

  1. (merah) ialahDirektori()? — tidak, perlu mencipta

  2. (biru) ialahDirektori()? — tidak, perlu mencipta

  3. (merah) mkdir()? — kejayaan

  4. (biru) mkdir()? — gagal

Seperti yang anda lihat benang biru gagal mencipta direktori. Walau bagaimanapun, ia sebenarnya dicipta, jadi hasilnya harus positif. Jika isDirectory() telah memanggil pada penghujungnya, hasilnya akan sentiasa betul.

Batasan tersembunyi

Bilangan fail dibuka pada masa yang sama oleh proses UNIX tertentu adalah terhad kepada nilai RLIMIT_NOFILE. Pada Android, ini biasanya 1024 tetapi berkesan (tidak termasuk deskriptor fail yang digunakan oleh rangka kerja) anda boleh menggunakan lebih sedikit (semasa ujian dengan Aktiviti kosong pada Android 8.0.0, terdapat kira-kira 970 deskriptor fail tersedia untuk digunakan). Apa yang berlaku jika anda cuba membuka lebih banyak lagi? Nah, fail itu tidak akan dibuka. Bergantung pada konteks, anda mungkin menghadapi pengecualian dengan sebab yang jelas (Terlalu banyak fail terbuka), sedikit mesej yang membingungkan (cth. Fail ini tidak boleh dibuka sebagai deskriptor fail; ia mungkin dimampatkan) atau hanya palsu sebagai nilai pulangan apabila anda biasanya menjangkakan benar. Lihat kod yang menunjukkan isu ini:

package pl.droidsonroids.edgetest

import android.content.res.AssetFileDescriptor
import android.support.test.InstrumentationRegistry
import org.junit.Assert
import org.junit.Test

class TooManyOpenFilesTest {
    //asset named "test" required
    @Test
    fun tooManyOpenFilesDemo() {
        val context = InstrumentationRegistry.getContext()
        val assets = context.assets
        val descriptors = mutableListOf<AssetFileDescriptor>()
        try {
            for (i in 0..1024) {
                descriptors.add(assets.openFd("test"))
            }
        } catch (e: Exception) {
            e.printStackTrace() //java.io.FileNotFoundException: This file can not be opened as a file descriptor; it is probably compressed
        }
        try {
            context.openFileOutput("test", 0)
        } catch (e: Exception) {
            e.printStackTrace() //java.io.FileNotFoundException: /data/user/0/pl.droidsonroids.edgetest/files/test (Too many open files)
        }

        val sharedPreferences = context.getSharedPreferences("test", 0)
        Assert.assertTrue(sharedPreferences.edit().putBoolean("test", true).commit())
    }
}
Salin selepas log masuk

Perhatikan bahawa, jika anda menggunakan #apply(), nilai itu tidak akan disimpan secara berterusan — jadi anda tidak akan mendapat sebarang pengecualian. Walau bagaimanapun, ia boleh diakses sehingga proses apl yang memegang bahawa contoh SharedPreferences dimatikan. Itu kerana pilihan yang dikongsi turut disimpan dalam ingatan.

Undeads benar-benar wujud

Orang mungkin berfikir bahawa zombi, hantu dan makhluk lain yang serupa wujud dalam fantasi dan fiksyen seram sahaja. Tetapi… ia adalah nyata dalam sains komputer! Istilah biasa sedemikian merujuk kepada proses zombi. Malah, fail mayat hidup juga boleh dibuat dengan mudah.

In Unix-like operating systems, file deletion is usually implemented by unlinking. The unlinked file name is removed from the file system (assuming that it is the last hardlink) but any already open file descriptors remain valid and usable. You can still read from and write to such a file. Here is the snippet:

import java.io.BufferedReader
import java.io.File
import java.io.FileReader

val file = File("test")
file.writeText("this is file content")

BufferedReader(FileReader(file)).use {
   println("deleted?: ${file.delete()}")
   println("content?: ${it.readLine()}")
}
Salin selepas log masuk

And a live demo.

Wrap up

First of all, remember that we can’t forget about the proper method calling order when creating non-existent directories. Furthermore, keep in mind that a number of files open at the same time is limited and not only files explicitly opened by you are counted. And the last, but not least, a trick with file deletion before the last usage can give you a little bit more flexibility.

Originally published at www.thedroidsonroids.com on September 27, 2017.

Atas ialah kandungan terperinci Kes Tepi yang Perlu Diingati. Fail Bahagian. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

sumber:dev.to
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan