จะสร้าง java.io.File ใหม่ในหน่วยความจำได้อย่างไร?


105

ฉันจะสร้างFile(จากjava.io) ใหม่ในหน่วยความจำไม่ใช่ในฮาร์ดดิสก์ได้อย่างไร

ฉันใช้ภาษา Java ฉันไม่ต้องการบันทึกไฟล์ในฮาร์ดไดรฟ์

ฉันเจอกับ API ที่ไม่ดี ( java.util.jar.JarFile) มันคาดหวังของFile file String filenameฉันไม่มีไฟล์ (เฉพาะbyte[]เนื้อหา) และสามารถสร้างไฟล์ชั่วคราวได้ แต่มันไม่ใช่วิธีแก้ปัญหาที่สวยงาม ฉันต้องการตรวจสอบความถูกต้องของโถที่เซ็นชื่อ

byte[] content = getContent();
File tempFile = File.createTempFile("tmp", ".tmp");
FileOutputStream fos = new FileOutputStream(tempFile);
fos.write(archiveContent);
JarFile jarFile = new JarFile(tempFile);
Manifest manifest = jarFile.getManifest();

ขอขอบคุณตัวอย่างวิธีการบรรลุการรับไฟล์ Manifest โดยไม่ต้องสร้างไฟล์ชั่วคราว


8
คุณแค่ต้องการไบต์ในหน่วยความจำ?
Sotirios Delimanolis

6
คุณกำลังพยายามทำอะไรกับสิ่งนี้File?
Jon Skeet

5
Fileโดยความหมายอยู่ในฮาร์ดไดรฟ์
Uwe Plonus

3
จุดประสงค์ของการสร้างไฟล์คืออะไรถ้าคุณไม่ต้องการให้อยู่ในหน่วยความจำถาวร?
Bhavik Shah

9
ว้าวการขาดจินตนาการใน StackOverflow นั้นน่าประหลาดใจ บางคนอาจต้องการไฟล์ในหน่วยความจำที่เรียบง่ายเนื่องจากใช้อินเทอร์เฟซที่ต้องใช้ไฟล์ ควรเขียนอินเทอร์เฟซสำหรับ InputStream แต่ไม่ใช่ ไฟล์ temp ดูเหมือนจะ overkill ดังนั้นควรใช้ไฟล์ java.io ในหน่วยความจำ
Novaterata

คำตอบ:


30

ไม่สามารถสร้างjava.io.Fileที่เก็บเนื้อหาไว้ในหน่วยความจำ (ฮีป Java) *

โดยปกติคุณจะใช้สตรีม ในการเขียนไปยังสตรีมในหน่วยความจำให้ใช้:

OutputStream out = new ByteArrayOutputStream();
out.write(...);

แต่น่าเสียดายที่สตรีมไม่สามารถใช้เป็นอินพุตได้java.util.jar.JarFileซึ่งตามที่คุณกล่าวถึงสามารถใช้ได้เฉพาะ a FileหรือStringที่มีพา ธ ไปยังไฟล์ JAR ที่ถูกต้องเท่านั้น ฉันเชื่อว่าการใช้ไฟล์ชั่วคราวเหมือนที่คุณทำอยู่เป็นทางเลือกเดียวเว้นแต่คุณต้องการใช้ API อื่น

หากคุณโอเคโดยใช้ API อื่นมีคลาสที่สะดวกในแพ็คเกจเดียวกันซึ่งตั้งชื่อว่าJarInputStreamคุณสามารถใช้ได้ เพียงห่อarchiveContentอาร์เรย์ของคุณใน a ByteArrayInputStreamเพื่ออ่านเนื้อหาของ JAR และแยกรายการ:

try (JarInputStream stream = new JarInputStream(new ByteArrayInputStream(archiveContent))) {
     Manifest manifest = stream.getManifest();
}

*) เห็นได้ชัดว่าเป็นไปได้ที่จะสร้างระบบไฟล์แบบเต็มที่อยู่ในหน่วยความจำเช่น RAM-disk แต่จะยังคงเป็น "บนดิสก์" (และไม่อยู่ในหน่วยความจำฮีป Java) เท่าที่กระบวนการ Java เกี่ยวข้อง


6
สิ่งนี้ไม่ตอบคำถามเนื่องจาก ByteArrayOutputStream ไม่สามารถใช้กับอินเทอร์เฟซที่ต้องใช้อ็อบเจ็กต์ไฟล์
FableBlaze

1
@FableBlaze คำตอบสำหรับคำถามนั้นคือ“ เป็นไปไม่ได้” คำตอบนี้พยายามใช้ในทางปฏิบัติและบอกสิ่งที่ผู้ใช้สามารถทำได้แทน คำตอบของ Andreas ชัดเจนกว่าและเป็นคำตอบที่ดีกว่า (พยายามที่จะตอบ)
haraldK

1
"เป็นไปไม่ได้" คงเป็นคำตอบที่ใช้ได้ในความคิดของฉัน อย่างไรก็ตามฉันคิดว่าระบบไฟล์ในหน่วยความจำ (ที่กล่าวถึงในความคิดเห็นของคำตอบของ Andreas) อาจถูกกล่าวถึงเช่นกันเพราะถ้าคุณไม่สามารถเขียนลงฮาร์ดไดรฟ์ได้ด้วยเหตุผลบางอย่างนั่นอาจเป็นวิธีแก้ปัญหา
FableBlaze

83

ฉันจะสร้างไฟล์ใหม่ (จาก java.io) ในหน่วยความจำไม่ใช่ในฮาร์ดดิสก์ได้อย่างไร

บางทีคุณอาจสับสนFileและStream:

  • Fileเป็นตัวแทนนามธรรมของไฟล์และไดเรกทอรีpathnames การใช้Fileอ็อบเจ็กต์คุณสามารถเข้าถึงข้อมูลเมตาของไฟล์ในระบบไฟล์และดำเนินการบางอย่างกับไฟล์บนระบบไฟล์นี้เช่นลบหรือสร้างไฟล์ แต่Fileชั้นเรียนไม่มีวิธีการอ่านและเขียนเนื้อหาของไฟล์
  • การอ่านและเขียนจากแฟ้มคุณกำลังใช้Streamวัตถุเช่นหรือFileInputStream FileOutputStreamสตรีมเหล่านี้สามารถสร้างขึ้นจากFileอ็อบเจ็กต์จากนั้นใช้เพื่ออ่านและเขียนไปยังไฟล์

คุณสามารถสร้างสตรีมตามบัฟเฟอร์ไบต์ที่อยู่ในหน่วยความจำโดยใช้ a ByteArrayInputStreamและ a ByteArrayOutputStreamเพื่ออ่านและเขียนไปยังไบต์บัฟเฟอร์ในลักษณะเดียวกับที่คุณอ่านและเขียนจากไฟล์ byteอาร์เรย์มีเนื้อหา "File ของ" คุณไม่ต้องการFileวัตถุแล้ว

ทั้งสตรีมFile...และByteArray...สตรีมสืบทอดจากjava.io.OutputStreamและjava.io.InputStreamตามลำดับเพื่อให้คุณสามารถใช้ซูเปอร์คลาสทั่วไปเพื่อซ่อนว่าคุณกำลังอ่านจากไฟล์หรือจากอาร์เรย์ไบต์


99
ฉันไม่แน่ใจว่านี่คือสิ่งที่ผู้โพสต์ต้องการหรือไม่ แต่ตัวอย่างหนึ่งเมื่อ "ไฟล์ในหน่วยความจำ" มีประโยชน์คือเมื่อคุณต้องการใช้ไลบรารีที่มีอยู่ซ้ำซึ่งต้องใช้ java.io.File เป็นพารามิเตอร์อินพุต ต้องการใช้ "ไฟล์" ที่เก็บไว้ในหน่วยความจำจริงๆ ในกรณีนั้นฉันคิดว่าวิธีแก้ปัญหาหนึ่งคือการใช้ Apache Commons VFS เพื่อสร้างอินสแตนซ์ DefaultFileSystemManager และใช้เพื่อสร้าง RamFileProvider ฉันจะเพิ่มสิ่งนี้เป็นคำตอบที่ถูกต้อง (สมบูรณ์ยิ่งขึ้น) แต่ดูเหมือนว่าคำถามนี้จะถูกปิดไปแล้วในช่วงหนึ่ง ...
Sorin Postelnicu

2
+1 ฉันกำลังมองหาวิธีการแก้ปัญหาแบบนี้ในการทดสอบหน่วยโดยไม่ต้องใช้ไฟล์จริง
GClaramunt

3
หากคุณไม่ต้องการสร้าง "ไฟล์จริง" คุณสามารถลองสร้างไฟล์ชั่วคราว ดูสำหรับcreateTempFile java.io.fileไฟล์นี้สามารถตั้งค่าให้ลบอัตโนมัติเมื่อออกจากการทดสอบหน่วย
Andrew-Dufresne

2
นี่ไม่ตอบคำถาม ดังที่ @SorinPostelnicu กล่าวไว้อย่างดีว่า "ไฟล์" ในหน่วยความจำเป็นสิ่งที่คล้ายกับระบบไฟล์ในหน่วยความจำหรือมากกว่านั้น
Felipe

1
อาจเป็นผลรวมกรณีการใช้งานของ OP และวิธีการที่มีคุณค่าในการลดเวลาแฝงด้วย i / o ดิสก์ระบบราคาแพง
Eddie B

6

คุณสามารถใช้ระบบไฟล์ในหน่วยความจำเช่นJimfs

นี่คือตัวอย่างการใช้งานจาก readme:

FileSystem fs = Jimfs.newFileSystem(Configuration.unix());
Path foo = fs.getPath("/foo");
Files.createDirectory(foo);

Path hello = foo.resolve("hello.txt"); // /foo/hello.txt
Files.write(hello, ImmutableList.of("hello world"), StandardCharsets.UTF_8);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.