


Comment Java utilise-t-il NIO pour optimiser les IO afin d'implémenter les fonctions de téléchargement et de téléchargement de fichiers??
May 12, 2023 pm 09:31 PM1 NIO的一些基礎(chǔ)預(yù)備知識(shí)
Java中IO流類的體系中BIO與NIO:https://blog.csdn.net/ZGL_cyy/article/details/104326458
Java IO體系與NIO和BIO體系面試題 :https://blog.csdn.net/ZGL_cyy/article/details/122836368
為什么使用NIO:因?yàn)閭鹘y(tǒng)IO文件傳輸速率低,所以選擇了NIO進(jìn)行文件的下載操作。NIO還有一個(gè)好處就是其中零拷貝可以實(shí)現(xiàn)減少內(nèi)存中數(shù)據(jù)的重復(fù),減少CPU操作的效果。所以相對(duì)于傳統(tǒng)IO,NIO有著效率高點(diǎn)的優(yōu)勢。
2 NIO為何較傳統(tǒng)的io速度較快
就拿單個(gè)io過程來看,首先時(shí)間主要花在了用戶態(tài)和內(nèi)核態(tài)的轉(zhuǎn)換上,其次,考慮將多個(gè)io的“合并”為一個(gè)io,這不就節(jié)省時(shí)間了嗎
相應(yīng)的NIO主要做了兩方面的提升
1.避免了用戶態(tài)和內(nèi)核態(tài)的交換,直接操作內(nèi)存,用戶態(tài)和內(nèi)核態(tài)的轉(zhuǎn)換是很費(fèi)時(shí)的,傳統(tǒng)的io寫入磁盤時(shí),用戶態(tài)的接口不能直接操作內(nèi)存,而是通過操作系統(tǒng)調(diào)用內(nèi)核態(tài)接口來進(jìn)行io。
2.利用buffer減少io的次數(shù),buffer化零為整”的寫入方式因?yàn)榇蟠鬁p小了尋址/寫入次數(shù),所以就降低了硬盤的負(fù)荷。
3.IO 是基于流來讀取的,而NIO則是基于塊讀取,面向流 的 I/O 系統(tǒng)一次一個(gè)字節(jié)地處理數(shù)據(jù)。一個(gè)輸入流產(chǎn)生一個(gè)字節(jié)的數(shù)據(jù),一個(gè)輸出流消費(fèi)一個(gè)字節(jié)的數(shù)據(jù)。為流式數(shù)據(jù)創(chuàng)建過濾器非常容易。鏈接幾個(gè)過濾器,以便每個(gè)過濾器只負(fù)責(zé)單個(gè)復(fù)雜處理機(jī)制的一部分,這樣也是相對(duì)簡單的。不利的一面是,面向流的 I/O 通常相當(dāng)慢。
一個(gè) 面向塊 的 I/O 系統(tǒng)以塊的形式處理數(shù)據(jù)。每一個(gè)操作都在一步中產(chǎn)生或者消費(fèi)一個(gè)數(shù)據(jù)塊。按塊處理數(shù)據(jù)比按(流式的)字節(jié)處理數(shù)據(jù)要快得多。但是面向塊的 I/O 缺少一些面向流的 I/O 所具有的優(yōu)雅性和簡單性。
4.非阻塞IO 和 異步IO的支持, 減少線程占有的??臻g,以及上下文切換
5.IO 多路復(fù)用的支持
6.Buffer 支持,所有讀寫操作都是基于 緩沖 來實(shí)現(xiàn)
7.NIO 支持 Direct Memory, 可以減少一次數(shù)據(jù)拷貝
8.Netty 零拷貝的支持
3 NIO實(shí)戰(zhàn)上傳下載
3.1 url下載文件
java NIO包提供了無緩沖情況下在兩個(gè)通道之間直接傳輸字節(jié)的可能。
為了讀來自URL的文件,需從URL流創(chuàng)建ReadableByteChannel :
ReadableByteChannel readableByteChannel = Channels.newChannel(url.openStream());
從ReadableByteChannel 讀取字節(jié)將被傳輸至FileChannel:
FileOutputStream fileOutputStream = new FileOutputStream(FILE_NAME); FileChannel fileChannel = fileOutputStream.getChannel();
然后使用transferFrom方法,從ReadableByteChannel 類下載來自URL的字節(jié)傳輸?shù)紽ileChannel:
fileOutputStream.getChannel().transferFrom(readableByteChannel, 0, Long.MAX_VALUE);
transferTo() 和 transferFrom() 方法比簡單使用緩存從流中讀更有效。依據(jù)不同的底層操作系統(tǒng),數(shù)據(jù)可以直接從文件系統(tǒng)緩存?zhèn)鬏數(shù)轿覀兊奈募?,而不必將任何字?jié)復(fù)制到應(yīng)用程序內(nèi)存中。
在Linux和UNIX系統(tǒng)上,這些方法使用零拷貝技術(shù),減少了內(nèi)核模式和用戶模式之間的上下文切換次數(shù)。
工具類:
/**NIO文件下載工具類 * @author olalu */ public class NioDownloadUtils { /** * @description: * @param file: 要下在文件 * @return: void */ public static void downloadDoc(File file,HttpServletResponse response) throws IOException { OutputStream outputStream = response.getOutputStream(); String contentType = Files.probeContentType(Paths.get(file.getAbsolutePath())); //設(shè)置響應(yīng)頭 response.setHeader("Content-Type", contentType); response.setHeader("Content-Disposition", "attachment;filename="+ new String(file.getName().getBytes("utf-8"),"ISO8859-1")); response.setContentLength((int) file.length()); //獲取文件輸入流 FileInputStream fileInputStream = new FileInputStream(file); //獲取輸出流通道 WritableByteChannel writableByteChannel = Channels.newChannel(outputStream); FileChannel fileChannel = fileInputStream.getChannel(); //采用零拷貝的方式實(shí)現(xiàn)文件的下載 fileChannel.transferTo(0,fileChannel.size(),writableByteChannel); //關(guān)閉對(duì)應(yīng)的資源 fileChannel.close(); outputStream.flush(); writableByteChannel.close(); } public static void downloadDoc(String path,HttpServletResponse response) throws IOException { File file = new File(path); if (!file.exists()){ throw new RuntimeException("文件不存在"); } downloadDoc(file,response); } }
3.2 通過NIO上傳文件
/** * 文件上傳方法 */ public static Result uploading(MultipartFile file) { //獲取文件名 String realName = file.getOriginalFilename(); String newName = null; if(realName != null && realName != ""){ //獲取文件后綴 String suffixName = realName.substring(realName.lastIndexOf(".")); //生成新名字 newName = UUID.randomUUID().toString().replaceAll("-", "")+suffixName; }else { return Result.fail("文件名不可為空"); } //創(chuàng)建流 FileInputStream fis = null; FileOutputStream fos = null; //創(chuàng)建通道 FileChannel inChannel = null; FileChannel outChannel = null; try { fis = (FileInputStream)file.getInputStream(); //開始上傳 fos = new FileOutputStream(UPLOAD_URL+"\\"+newName); //通道間傳輸 inChannel = fis.getChannel(); outChannel = fos.getChannel(); //上傳 inChannel.transferTo(0,inChannel.size(),outChannel); }catch (IOException e){ return Result.fail("文件上傳路徑錯(cuò)誤"); }finally { //關(guān)閉資源 try { if (fis != null) { fis.close(); } if (fos != null) { fos.close(); } if (inChannel != null) { inChannel.close(); } if (outChannel != null) { outChannel.close(); } } catch (IOException e) { e.printStackTrace(); } } return Result.ok(newName); }
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Outils d'IA chauds

Undress AI Tool
Images de déshabillage gratuites

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Clothoff.io
Dissolvant de vêtements AI

Video Face Swap
échangez les visages dans n'importe quelle vidéo sans effort grace à notre outil d'échange de visage AI entièrement gratuit?!

Article chaud

Outils chauds

Bloc-notes++7.3.1
éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Sujets chauds

Il existe trois méthodes courantes pour traverser la carte dans Java: 1. Utilisez l'entrée pour obtenir des clés et des valeurs en même temps, ce qui convient à la plupart des scénarios; 2. Utilisez un ensemble de touches ou des valeurs pour traverser respectivement les clés ou les valeurs; 3. Utilisez Foreach de Java8 pour simplifier la structure du code. EntrySet renvoie un ensemble de set contenant toutes les paires de valeurs de clé, et chaque boucle obtient l'objet Map.Entry, adapté à un accès fréquent aux touches et aux valeurs; Si seules les clés ou les valeurs sont nécessaires, vous pouvez appeler respectivement KeySet () ou Values (), ou vous pouvez obtenir la valeur via map.get (key) lors de la traversée des clés; Java 8 peut utiliser ForEach ((clé, valeur) - & gt

Facultatif peut clairement exprimer les intentions et réduire le bruit du code pour les jugements nuls. 1. Facultatif. Par exemple, lors de la prise de valeurs des cartes, Orelse peut être utilisée pour fournir des valeurs par défaut, afin que la logique soit plus claire et concise; 2. Utilisez des cartes d'appels de cha?ne pour atteindre les valeurs imbriquées pour éviter en toute sécurité le NPE, et terminer automatiquement si un lien est nul et renvoie la valeur par défaut; 3. Le filtre peut être utilisé pour le filtrage conditionnel, et les opérations ultérieures ne continueront à être effectuées que si les conditions sont remplies, sinon elle sautera directement à Orelse, qui convient au jugement commercial léger; 4. Il n'est pas recommandé de surutiliser facultatif, tels que des types de base ou une logique simple, ce qui augmentera la complexité, et certains scénarios reviendront directement à NU.

La solution de contournement principale pour la rencontre de Java.io.NotSerializableException est de s'assurer que toutes les classes qui doivent être sérialisées implémentent l'interface sérialisable et de vérifier le support de sérialisation des objets imbriqués. 1. Ajouter des ouvrages ImplementSerialisables à la classe principale; 2. Assurez-vous que les classes correspondantes de champs personnalisées de la classe implémentent également sérialisables; 3. Utilisez transitoire pour marquer les champs qui n'ont pas besoin d'être sérialisés; 4. Vérifiez les types non sérialisés dans les collections ou les objets imbriqués; 5. Vérifiez quelle classe n'implémente pas l'interface; 6. Considérez la conception de remplacement pour les classes qui ne peuvent pas être modifiées, telles que la sauvegarde des données clés ou l'utilisation de structures intermédiaires sérialisables; 7. Envisagez de modifier

En Java, comparable est utilisé pour définir les règles de tri par défaut en interne et le comparateur est utilisé pour définir plusieurs logiques de tri à l'extérieur. 1. Comparable est une interface implémentée par la classe elle-même. Il définit l'ordre naturel en réécrivant la méthode compareto (). Il convient aux classes avec des méthodes de tri fixe et le plus couramment utilisées, telles que la cha?ne ou le rendement. 2. Comparateur est une interface fonctionnelle définie à l'extérieur, implémentée via la méthode compare (), adaptée aux situations où plusieurs méthodes de tri sont requises pour la même classe, le code source de classe ne peut pas être modifié ou la logique de tri est souvent modifiée. La différence entre les deux est que comparable ne peut définir qu'une logique de tri et doit modifier la classe elle-même, tandis que comparable

La référence de la méthode est un moyen de simplifier l'écriture des expressions de lambda en Java, ce qui rend le code plus concis. Ce n'est pas une nouvelle syntaxe, mais un raccourci vers les expressions de lambda introduit par Java 8, adapté au contexte des interfaces fonctionnelles. Le noyau consiste à utiliser directement les méthodes existantes comme implémentations des interfaces fonctionnelles. Par exemple, System.out :: println est équivalent à s-> System.out.println (s). Il existe quatre formes principales de référence de méthode: 1. Référence de méthode statique (className :: staticMethodName); 2. Référence de la méthode d'instance (liaison à un objet spécifique, instance :: MethodName); 3 et 3

Pour faire face aux problèmes de codage des personnages en Java, la clé est de spécifier clairement le codage utilisé à chaque étape. 1. Spécifiez toujours le codage lors de la lecture et de l'écriture de texte, utilisez InputStreamReader et OutputStreamWriter et transmettez un jeu de caractères explicite pour éviter de s'appuyer sur le codage par défaut du système. 2. Assurez-vous que les deux extrémités sont cohérentes lors du traitement des cha?nes sur la limite du réseau, définissez l'en-tête de type contenu correct et spécifiez explicitement le codage avec la bibliothèque. 3. Utilisez String.getBytes () et Newstring (octet []) avec prudence, et spécifiez toujours manuellement StandardCharsets.Utf_8 pour éviter la corruption des données causée par les différences de plate-forme. En bref, par

Il existe trois fa?ons courantes d'analyser JSON en Java: utilisez Jackson, GSON ou Org.json. 1. Jackson convient à la plupart des projets, avec de bonnes performances et des fonctions complètes, et prend en charge la conversion et la cartographie de l'annotation entre les objets et les cordes JSON; 2. GSON est plus adapté aux projets Android ou aux besoins légers, et est simple à utiliser mais légèrement inférieur dans la gestion des structures complexes et des scénarios haute performance; 3.org.json convient aux taches simples ou aux petits scripts, et n'est pas recommandé pour les grands projets en raison de son manque de flexibilité et de sécurité de type. Le choix doit être décidé en fonction des besoins réels.

Comment créer rapidement de nouveaux e-mails dans Outlook est le suivant: 1. La version de bureau utilise la clé de raccourci Ctrl Shift M pour faire appara?tre directement une nouvelle fenêtre de messagerie; 2. La version Web peut créer de nouveaux e-mails en un clic en créant un signet contenant JavaScript (tels que javascript: document.QuerySelector ("divrole = 'bouton'"). Click ()); 3. Utilisez des plug-ins de navigateur (tels que Vimium, CRXMouseEstres) pour déclencher le bouton "New Mail"; 4. Les utilisateurs de Windows peuvent également sélectionner "nouveau courrier" en cliquant avec le bouton droit sur l'ic?ne Outlook de la barre des taches
