getResourceAsStream () เทียบกับ FileInputStream


173

ผมพยายามที่จะโหลดไฟล์ใน webapp หนึ่งและผมได้รับข้อยกเว้นเมื่อฉันใช้FileNotFound อย่างไรก็ตามการใช้เส้นทางเดียวกันผมก็สามารถที่จะโหลดไฟล์เมื่อฉันไม่FileInputStream getResourceAsStream()ความแตกต่างระหว่างสองวิธีคืออะไรและทำไมถึงทำงานในขณะที่อีกวิธีหนึ่งไม่ได้

คำตอบ:


256

java.io.Fileและภริยาทำหน้าที่ในระบบไฟล์ดิสก์ภายใน สาเหตุที่แท้จริงของปัญหาของคุณคือเส้นทางที่สัมพันธ์java.ioนั้นขึ้นอยู่กับไดเรกทอรีการทำงานปัจจุบัน นั่นคือไดเรกทอรีที่ JVM (ในกรณีของคุณ: เว็บเซิร์ฟเวอร์หนึ่งรายการ) เริ่มต้นขึ้น ตัวอย่างนี้อาจจะเป็นC:\Tomcat\binหรือสิ่งที่แตกต่างอย่างสิ้นเชิง แต่ไม่ C:\Tomcat\webapps\contextnameหรือสิ่งที่คุณคาดหวังให้ C:\Eclipse\workspace\projectnameในโครงการคราสปกติที่จะเป็น คุณสามารถเรียนรู้เกี่ยวกับไดเรกทอรีการทำงานปัจจุบันด้วยวิธีต่อไปนี้:

System.out.println(new File(".").getAbsolutePath());

อย่างไรก็ตามไดเรกทอรีการทำงานไม่สามารถควบคุมได้โดยทางโปรแกรม คุณควรใช้พา ธสัมบูรณ์ในFileAPI แทนการใช้พา ธ สัมพัทธ์ C:\full\path\to\file.extเช่น

คุณไม่ต้องการ hardcode หรือเดาเส้นทางสัมบูรณ์ในแอปพลิเคชัน Java (เว็บ) นั่นเป็นเพียงปัญหาการพกพา (เช่นมันทำงานในระบบ X แต่ไม่ใช่ในระบบ Y) การปฏิบัติปกติคือการวางทรัพยากรประเภทนั้นในclasspathหรือเพื่อเพิ่มเส้นทางแบบเต็มไปยัง classpath (ใน IDE เช่น Eclipse ที่เป็นsrcโฟลเดอร์และ "เส้นทางสร้าง" ตามลำดับ) วิธีนี้คุณสามารถคว้าพวกเขาด้วยความช่วยเหลือของClassLoaderโดย หรือClassLoader#getResource() ClassLoader#getResourceAsStream()มันสามารถที่จะหาไฟล์ที่เกี่ยวข้องกับ "root" ของ classpath ในขณะที่คุณคิดออกโดยบังเอิญ ใน webapplications (หรือแอปพลิเคชันอื่น ๆ ที่ใช้ classloaders หลายรายการ) ขอแนะนำให้ใช้สิ่งClassLoaderที่ถูกส่งคืนโดยThread.currentThread().getContextClassLoader()สิ่งนี้เพื่อให้คุณสามารถดู "นอก" บริบทของ webapp ได้เช่นกัน

ทางเลือกใน webapps ก็คือและคู่ServletContext#getResource() ServletContext#getResourceAsStream()สามารถเข้าถึงไฟล์ที่อยู่ในwebโฟลเดอร์สาธารณะของโครงการ webapp รวมถึง/WEB-INFโฟลเดอร์ ที่ServletContextมีอยู่ใน servlets โดยgetServletContext()วิธีการสืบทอดคุณสามารถเรียกมันตามสภาพ

ดูสิ่งนี้ด้วย:


5
@khylo: ที่เกี่ยวข้อง: stackoverflow.com/questions/7952090/…
BalusC

27

getResourceAsStream เป็นวิธีที่เหมาะสมในการทำเพื่อเว็บแอพ (ตามที่คุณได้เรียนรู้แล้ว)

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


3
+1 - แม้ว่า "ไม่สามารถทำงานได้" นั้นแรงเกินไป (การอ่านจากระบบไฟล์สามารถทำงานได้ แต่การทำแบบพกพานั้นเป็นเรื่องยุ่งยาก ... และโค้ดอื่น ๆ อีกมากมายโดยเฉพาะอย่างยิ่งหากทรัพยากรอยู่ใน JAR)
สตีเฟนซี

1
ดัฟฟี่คำตอบที่ดีมากและคุณอธิบายว่าความผิดพลาดของฉันคืออะไร แต่ BalusC มีรายละเอียดมากมาย - ฉันคิดว่าคำตอบของเขาจะเป็นประโยชน์สำหรับผู้ที่ต้องการทราบรายละเอียดภายในเช่นกัน หวังว่าคุณจะไม่รังเกียจฉันที่จะเปลี่ยนคำตอบที่ยอมรับให้กับเขา!
Vivin Paliath

@ สตีเฟ่น - ฉันไม่คิดว่า "ไม่สามารถทำงานได้" แข็งแกร่งเกินไป แม้แต่สิ่งที่ง่ายเหมือนการปรับใช้บนเซิร์ฟเวอร์สองเครื่องที่มีเส้นทางที่แตกต่างกันไปยังเซิร์ฟเวอร์แอปจะทำให้แตก ประเด็นก็คือคุณต้องทำให้ WAR ของคุณอยู่ในตัวเองมากที่สุด ประเด็นของคุณถูกต้อง แต่ฉันจะยึดคำพูดของฉัน
duffymo

14

FileInputStream จะโหลดพา ธ ไฟล์ที่คุณส่งไปยัง Constructor ซึ่งสัมพันธ์กับไดเร็กทอรีการทำงานของกระบวนการ Java โดยปกติแล้วจะอยู่ในคอนเทนเนอร์ของเว็บนี่เป็นสิ่งที่คล้ายกับbinโฟลเดอร์

getResourceAsStream()จะโหลดพา ธ ไฟล์ที่สัมพันธ์กับ classpath ของแอปพลิเคชันของคุณ


12

FileInputStreamระดับทำงานโดยตรงกับระบบแฟ้มพื้นฐาน หากไฟล์ดังกล่าวไม่มีอยู่จริงจะไม่สามารถเปิดได้ getResourceAsStream()วิธีการทำงานแตกต่างกัน มันพยายามค้นหาและโหลดทรัพยากรโดยใช้ClassLoaderคลาสที่มีการเรียกใช้ สิ่งนี้ทำให้สามารถค้นหาได้เช่นทรัพยากรที่ฝังอยู่ในjarไฟล์


ไฟล์ภายใน jar ยังคง "อยู่" ในระบบไฟล์ แต่มีอยู่ในไฟล์อื่น ๆ
ด้าน b

1
ใช่แน่นอน แต่พวกเขามักจะไม่ได้เห็นสิ่งที่เป็นหน่วยงานอิสระในระบบไฟล์เว้นแต่ว่าคุณจะรู้ว่าjarรูปแบบไฟล์และความหมายของแอปพลิเคชันเกิดขึ้นได้อย่างไร และในชวาความเหมาะสมClassLoaderอาจมีความรู้นี้ในขณะที่คนธรรมดาFileInputStreamไม่มี
เดิร์

7

classname.getResourceAsStream () โหลดไฟล์ผ่าน classloader ของ classname หากคลาสมาจากไฟล์ jar นั่นคือที่ที่จะโหลดรีซอร์ส

FileInputStream ใช้เพื่ออ่านไฟล์จากระบบไฟล์


0

ฉันมาที่นี่โดยแยกทั้งประเพณีโดยทำเครื่องหมายเป็นไฟล์อ่าน (java.io) และทรัพยากรอ่าน (ClassLoader.getResourceAsStream ())

อ่านไฟล์ - 1. ทำงานบนระบบไฟล์โลคัล 2. พยายามค้นหาไฟล์ที่ร้องขอจากไดเร็กทอรี JVM ปัจจุบันที่เปิดใช้เป็นรูท 3. จะเป็นการดีหากใช้ไฟล์สำหรับการประมวลผลในตำแหน่งที่กำหนดไว้ล่วงหน้าเช่น / dev / files หรือ C: \ Data

การอ่านทรัพยากร - 1. ทำงานบนเส้นทางคลาส 2. พยายามค้นหาไฟล์ / ทรัพยากรใน classpath ปัจจุบันหรือพาเรนต์ 3. ดีเลิศเมื่อพยายามโหลดไฟล์จากไฟล์ที่บรรจุเช่น war หรือ jar

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.