.NET Framework 4 檔案IO讀寫的增強 激動人心的強大 或許正是你所期待的 基類庫中的新增內容 轉自msdn雜誌
CLR 全面透析
.NET Framework 4 基類庫中的新增內容
使用 Microsoft .NET 的每個人幾乎都會用到基類庫 (BCL)。一個更好的 BCL 幾乎可以惠及每一位託管程式碼開發人員。 此專欄重點介紹 .NET 4 Beta 1 在 BCL 中新增的功能。
先前的文章中已經介紹了其中的三項新增功能 — 首先,讓我們簡單回顧一下:
- 支援程式碼約定
- 並行擴充套件(任務、併發集合和協調資料結構)
- 支援元組
接下來,本文將主要介紹另外三項新增功能: - 檔案 IO 改進
- 支援記憶體對映檔案
- 經過排序的集集合
由於篇幅所限,本文無法介紹所有最新的 BCL 改進,不過,BCL 團隊部落格很快會在 blogs.msdn.com/bclteam 上發表相關文章,您可以一睹為快。
- 支援任意大整數
- 介面和委託上的泛型方差批註
- 允許訪問 32 位和 64 位登錄檔檢視以及建立可變登錄檔項
- 全球化資料更新
- 改進了 System.Resourcesresource 查找回退邏輯
- 壓縮改進
我們還計劃介紹 Beta 2 的部分其他功能和改進,大約在 Beta 2 推出時,您可以在 BCL 團隊部落格中瞭解這些功能和改進的相關資訊。
程式碼約定
在 .NET Framework 4 中,BCL 的一個主要新增功能是程式碼約定。 利用這個新庫,您可以通過一種與語言無關的方法在程式碼中指定前置條件、後置條件和物件不變數。 Melitta Andersen 在 2009 年 8 月期 MSDN 雜誌的“CLR 全面透析”專欄中,對程式碼約定進行了詳細介紹。
並行擴充套件
隨著多核處理器在客戶端更為重要以及大規模並行伺服器的應用更為廣泛,幫助程式設計師輕鬆使用所有這些處理器顯得比以往任何時候都重要。 在 .NET 4 中,BCL 的另外一項主要新增功能是並行擴充套件 (PFX) 功能,該功能由平行計算平臺團隊提供。 PFX 包括任務並行庫 (TPL)、協調資料結構、併發集合和並行 LINQ (PLINQ) — 在編寫可利用多核計算機的程式碼時,這些功能可以簡化此類程式碼的編寫。 可以在 Stephen Toub 和 Hazim Shafi 文章中找到更多背景上 PFX"改進的支援並行度,在下一版本的 Visual Studio 中的"在 2008 年 10 月聯機
元組
在 .NET 4 中,BCL 的另一項新增功能是支援元組,元組類似於可以動態建立的匿名類。 元組是很多功能語言和動態語言(如 F# 和 Iron Python)中使用的一種資料結構。 通過在 BCL 中提供通用元組型別,有助於更好地實現語言互操作性。 許多程式設計師發現元組使用起來非常方便,尤其是從方法返回多個值時更是如此。因此,就連 C# 或 Visual Basic 開發人員也會發現它們很有用。 在 2009 年 7 月期 MSDN 雜誌的“CLR 全面透析”專欄中,Matt Ellis 介紹了 .NET 4 中新增的對元組的支援。
檔案 IO 改進
我們未詳細介紹的一個 .NET 4 新增功能是 System.IO.File 中新增的用於讀取和寫入文字檔案的方法。 自 .NET 2.0 以來,如果需要讀取文字檔案中的行,可以呼叫 File.ReadAllLines 方法,該方法以字串陣列的形式返回檔案中的所有行。 下面的程式碼使用 File.ReadAllLines 讀取文字檔案中的行,並將行的長度及行本身寫入控制檯:
string[] lines = File.ReadAllLines("file.txt"); foreach (var line in lines) { Console.WriteLine("Length={0}, Line={1}", line.Length, line); }
遺憾的是,上面的程式碼存在一個不易察覺的問題。 這個問題是由於 ReadAllLines 返回陣列造成的。ReadAllLines 必須讀取所有行並分配要返回的陣列,然後才能返回。 對於相對較小的檔案而言,這並不太糟,但對於包含數百萬行的大文字檔案,就會產生問題。 假設要開啟一個文字檔案格式的電話簿或 900 頁小說。 在將所有行載入到記憶體中之前,ReadAllLines 始終處於阻止狀態。 這不僅導致記憶體使用效率低下,還會延遲對行的處理,因為在所有行都讀入記憶體之後,才能訪問第一行。
要解決這個問題,可以使用 TextReader 開啟此檔案,然後將檔案的行逐一讀入記憶體。 儘管該方法行之有效,但並不像呼叫 File.ReadAllLines 那樣簡單:
using (TextReader reader = new StreamReader("file.txt")) { string line; while ((line = reader.ReadLine()) != null) { Console.WriteLine("Length={0}, Line={1}", line.Length, line); } }
在 .NET 4 中,我們為 File 新增了一個名為 ReadLines 的方法(相對於 ReadAllLines),該方法返回 IEnumerable<string> 而不是 string[]。 這個新增方法的效率要高很多,因為它不是將所有行一次性載入到記憶體中,而是每次讀取一行。 下面的程式碼使用 File.ReadLines 高效讀取檔案中的行,使用起來和效率較低的 File.ReadAllLines 一樣方便:
IEnumerable<string> lines = File.ReadLines(@"verylargefile.txt"); foreach (var line in lines) { Console.WriteLine("Length={0}, Line={1}", line.Length, line); }
請注意,對 File.ReadLines 的呼叫會立即返回。 您不必再等所有行都讀入記憶體,即可對行進行迴圈訪問。 實際上,檔案的讀取操作是在 Foreach 迴圈迭代的驅動之下進行的。 由於可以在讀取行的同時開始處理行,因此該方法顯著提高了可感知的程式碼效能;此外,由於每次只讀取一行,因此還大大提高了效率。 使用 File。ReadLines 的另一個新增功能是允許在需要時提前中止迴圈,而不必浪費時間讀取不需要的其他行。
我們還為 File.WriteAllLines 新增了一些過載方法,這些過載方法採用 IEnumerable<string> 引數,與採用 string[] 引數的現有過載方法類似。 此外,我們還新增了一個名為 AppendAllLines 的方法,該方法使用 IEnumerable<string> 引數向檔案追加行。 利用這些新增的方法,不必傳入陣列,就可以方便地向檔案寫入或追加行。 這意味著,如果有一個字串集合,可以直接將它傳遞給這些方法,而無需先將其轉換為字串陣列。
在 BCL 中,使用 IEnumerable<T>(而非陣列)的好處不止於此。 以檔案系統列舉 API 為例。 在以往的 Framework 版本中,要獲取目錄中的檔案,需要呼叫 DirectoryInfo. GetFiles 等方法,此類方法可返回 FileInfo 物件陣列。 然後,可以迴圈訪問 FileInfo 物件以獲取關於檔案的資訊,例如每個檔案的名稱和長度。具體程式碼如下所示:
DirectoryInfo directory = new DirectoryInfo(@"//share/symbols"); FileInfo[] files = directory.GetFiles(); foreach (var file in files) { Console.WriteLine("Name={0}, Length={1}", file.Name, file.Length); }
上面的程式碼存在兩個問題。 第一個問題不會令您感到吃驚,因為與 File.ReadAllLines 的問題一樣,此問題是由於 GetFiles 返回陣列造成的。 GetFiles 必須從檔案系統中檢索目錄中的完整檔案列表並分配要返回的陣列,然後才能返回。 這意味著,必須在檢索了所有檔案之後,才能獲得第一批結果,這種情況下,記憶體的使用率很低。 如果目錄包含一百萬個檔案,就必須先檢索全部一百萬個檔案並分配長度為一百萬的陣列。
上面的程式碼還有一個更為隱蔽的問題。 FileInfo 例項是通過將檔案路徑傳遞給 FileInfo 的建構函式建立的。FileInfo 的各個屬性(如 Length 和 CreationTime)是在首次訪問 FileInfo 的某個屬性時初始化的。 首次訪問某個屬性時,會呼叫 FileInfo.Refresh,從而呼叫作業系統從檔案系統中檢索檔案的各個屬性。 這樣,就避免了在屬性從未使用時進行呼叫來檢索資料,如果使用了屬性,則有助於確保在首次訪問時資料未過時。 對於 FileInfo 的一次性例項,這非常有用,但當列舉目錄中的內容時,可能會產生問題,因為這意味著將多次呼叫檔案系統來獲取檔案屬性。 遍歷結果時,進行多次呼叫會影響效能。 如果要列舉遠端檔案共享的內容,此問題尤為突出,因為這意味著通過網路對遠端計算機進行再一次往返呼叫。
在 .NET 4 中,我們已經解決了這兩個問題。 為了解決第一個問題,我們在 Directory 和 DirectoryInfo 中添加了一些新方法,這些方法將返回 IEnumerable<T> 而非陣列。
與 File.ReadLines 一樣,這些基於 IEnumerable<T> 的新方法比基於陣列的舊方法更高效。 下面的程式碼已更新為使用 .NET 4 的 DirectoryInfo. EnumerateFiles 方法而非 DirectoryInfo.GetFiles:
DirectoryInfo directory = new DirectoryInfo(@"//share/symbols"); IEnumerable<FileInfo> files = directory.EnumerateFiles(); foreach (var file in files) { Console.WriteLine("Name={0}, Length={1}", file.Name, file.Length); }
與 GetFiles 不同,EnumerateFiles 不必在檢索完所有檔案之前一直處於阻止狀態,也不必分配陣列。 相反,它將立即返回,從檔案系統返回每一個檔案時,可以對其進行處理。
為解決第二個問題,DirectoryInfo 現在使用作業系統在列舉法。 實際上,DirectoryInfo 在列舉過程中為獲得檔案系統內容而呼叫的基礎 Win32 函式包含有關每個檔案的資料,例如長度和建立時間。 現在,在初始化通過 DirectoryInfo 的基於陣列的舊方法和基於 IEnumerable<T> 的新方法返回的 FileInfo 和 DirectoryInfo 例項時,我們將使用這些資料。 這意味著,在前面的程式碼中,當呼叫 file.Length 時,由於該資料已初始化,因此不對檔案系統進行任何多餘基礎呼叫即可檢索檔案長度。
總之,通過 File 和 Directory 的基於 IEnumerable<T> 的新方法,可以實現一些有用的方案。 請考慮以下程式碼:
var errorlines = from file in Directory.EnumerateFiles(@"C:/logs", "*.log") from line in File.ReadLines(file) where line.StartsWith("Error:", StringComparison.OrdinalIgnoreCase) select string.Format("File={0}, Line={1}", file, line); File.WriteAllLines(@"C:/errorlines.log", errorlines);
這段程式碼使用 Directory 和 File 的新方法以及 LINQ,高效查詢副檔名為 .log 的檔案,並在這些檔案中查詢以“Error:”開頭的行。 然後,該查詢將結果投影到新的字串序列中,每個字串都進行格式化以顯示檔案路徑和錯誤行。 最後,使用 File. WriteAllLines 將錯誤行寫入名為“errorlines.log”的新檔案,而不必將錯誤行轉換為陣列。 該程式碼的最大優點在於非常高效。 我們無需將整個檔案列表讀入記憶體,也無需將檔案的全部內容讀入記憶體。 無論 C:/logs 包含 10 個檔案還是 100 萬個檔案,無論檔案包含 10 行還是 100 萬行,上面的程式碼都會使用盡量少的記憶體高效執行。
記憶體對映檔案
對記憶體對映檔案的支援是 .NET Framework 4 中的另一項新增功能。記憶體對映檔案可用於編輯大檔案或為程序間通訊 (IPC) 建立共享記憶體。 記憶體對映檔案可用於編輯大檔案或為程序間通訊 (IPC) 建立共享記憶體。 通過記憶體對映檔案,可以將檔案對映到程序的地址空間。 對映之後,應用程式通過對記憶體進行讀寫操作,即可訪問或修改檔案的內容。 因為檔案是通過作業系統的記憶體管理器訪問的,所以檔案自動分割槽到很多頁面中,頁面則根據需要換入或換出記憶體。 因為不必自己進行記憶體管理,使得大檔案的處理更為方便。 在這種方式下,還可以對檔案進行完全隨機訪問,而無需進行查詢。
記憶體對映檔案可在沒有支援檔案的情況下建立。 這類記憶體對映檔案由系統分頁檔案支援(僅當存在系統分頁檔案並且內容需要換出記憶體時)。 記憶體對映檔案可供多個程序共享,這意味著,通過記憶體對映檔案為程序間通訊建立共享記憶體是一種很好的方法。 每個對映都可擁有一個與自己關聯的名稱,以便其他程序用來開啟該記憶體對映檔案。
要使用記憶體對映檔案,必須首先使用 System.IO.MemoryMappedFiles.MemoryMappedFile 類的以下某個靜態工廠方法建立 MemoryMappedFile 例項:
- CreateFromFile
- CreateNew
- CreateOrOpen
- OpenExisting
然後,可以建立一個或多個檢視,將檔案實際對映到程序地址空間中。 每個檢視都可對映全部或部分記憶體對映檔案,並且檢視可以重疊。
如果檔案的大小大於程序可用於對映的邏輯記憶體空間(在 32 位計算機中為 2GB),就需要使用多個檢視。通過呼叫 MemoryMappedFile 物件的 CreateViewStream 或 CreateViewAccessor 方法,可以建立檢視。CreateViewStream 返回 MemoryMappedFileViewStream 例項,該例項繼承自 System.IO.UnmanagedMemoryStream。 它可以像 Framework 中的任何其他 Stream 一樣使用。 另一方面,CreateViewAccessor 返回 MemoryMappedFileViewAccessor 例項,該例項繼承自新增的 System.IO.UnmanagedMemoryAccessorclass。 UnmanagedMemoryAccessor 支援隨機訪問,而 UnmanagedMemoryStream 支援順序訪問。
新增方法...... System.IO.file 上
- public static IEnumerable<string>ReadLines(string path)
- public static void WriteAllLines(string path, IEnumerable<string> contents)
- public static void AppendAllLines(string path, IEnumerable<string> contents)
... System.IO.directory 上
- public static Enumerable<string>EnumerateDirectories(string path)
- public static IEnumerable<string>EnumerateFiles(string path)
- public staticIEnumerable<string>EnumerateFileSystemEntries(string path)
... System.IO.DirectoryInfo 上
- publicIEnumerable<DirectoryInfo>EnumerateDirectories()
- publicIEnumerable<FileInfo>EnumerateFiles()
- publicIEnumerable<FileSystemInfo>EnumerateFileSystemInfos()
下面的示例說明如何使用記憶體對映檔案為 IPC 建立共享記憶體。 程序 1(如圖 1 所示)通過在 CreateNew 方法中指定記憶體對映檔案的名稱和容量(以位元組為單位),建立一個新的 MemoryMappedFile 例項。 這樣將建立一個由系統分頁檔案支援的記憶體對映檔案。 請注意,在系統內部,指定的容量會向上取整為下一個系統頁面大小倍數(如果您感興趣,可以從 .NET 4 中新增的 Environment.System- PageSize 獲取系統頁面大小)。 接下來,使用 CreateViewStream 建立一個檢視流,並使用 BinaryWriter 的例項將“Hello Word!”寫入該流中。 然後,啟動第二個程序。
程序 2(如圖 2 所示)通過指定適當的記憶體對映檔名稱,使用 OpenExisting 方法開啟現有的記憶體對映檔案。 然後,建立一個檢視流並使用 BinaryReader 的例項讀取上述字串。
圖 1 程序 1
using (varmmf = MemoryMappedFile.CreateNew("mymappedfile", 1000)) using (var stream = mmf.CreateViewStream()) { var writer = new BinaryWriter(stream); writer.Write("Hello World!"); varstartInfo = new ProcessStartInfo("process2.exe"); startInfo.UseShellExecute = false; Process.Start(startInfo).WaitForExit(); }
圖 2 程序 2
using (varmmf = MemoryMappedFile.OpenExisting("mymappedfile")) using (var stream = mmf.CreateViewStream()) { var reader = new BinaryReader(stream); Console.WriteLine(reader.ReadString()); }
SortedSet<T>
除了 System.Collections.Concurrent(PFX 的組成部分)中新增的集合外,.NET Framework 4 還在 System.Collections.Generic 中提供了一個新的集集合,稱為 SortedSet<T>。 與 .NET 3.5 中新增的 HashSet<T> 一樣,SortedSet<T> 也是由唯一元素組成的集合,但與 HashSet<T> 不同,SortedSet<T> 的元素按排序順序排列。
SortedSet<T> 是使用自平衡紅黑樹實現的,其插入、刪除和查詢操作的效能複雜度為 O(log n)。 相比而言,HashSet<T> 的插入、刪除和查詢操作的效能稍好,複雜度為 O(1)。 如果只需常規用途的集,大多數情況下應使用 HashSet<T>。 但是,如果需要按排序順序排列的元素、獲取特定範圍內的元素子集,或者獲取最小或最大元素,則應使用 SortedSet<T>。 以下程式碼說明如何使用 SortedSet<T> 處理整數:
var set1 = new SortedSet<int>() { 2, 5, 6, 2, 1, 4, 8 }; bool first = true; foreach (var i in set1) { if (first) { first = false; } else { Console.Write(","); } Console.Write(i); } // Output: 1,2,4,5,6,8
該集是使用 C# 的集合初始值設定項語法建立和初始化的。 請注意,整數不是以特定順序新增到集中的。 另外請注意,添加了兩次 2。 顯然,遍歷 set1 的元素時,整數以排序順序排列,並且該集僅包含一個 2。 與 HashSet<T> 一樣,SortedSet<T> 的 Add 方法返回布林型別的值,用於確定是成功添加了項 (true) 還是因集中已有該項而未能新增 (false)。
圖 3 說明如何獲取集中的最大和最小元素,以及如何獲取特定範圍內的元素子集。
圖 3 獲取元素的最大、最小值和子集檢視
var set1 = new SortedSet<int>() { 2, 5, 6, 2, 1, 4, 8 }; Console.WriteLine("Min: {0}", set1.Min); Console.WriteLine("Max: {0}", set1.Max); var subset1 = set1.GetViewBetween(2, 6); Console.Write("Subset View: "); bool first = true; foreach (var i in subset1) { if (first) { first = false; } else { Console.Write(","); } Console.Write(i); } // Output: // Min: 1 // Max: 8 // Subset View: 2,4,5,6
GetViewBetween 方法返回原始集的檢視。 這意味著對檢視所做的任何更改都將反映在原始檢視中。 例如,如果在上述程式碼中將 3 新增到 subset1,實際上會新增到 set1。 請注意,不能將項新增到指定範圍之外的檢視。 例如,如果試圖在上述程式碼中將一個 9 新增到 subset1,則會產生 Argument-Exception,因為檢視在 2 和 6 之間。
歡迎試用
本專欄介紹的 BCL 新增功能是 .NET Framework 4 提供的新增功能的一部分。 歡迎關注 BCL 團隊部落格中即將發表的關於部分其他 BCL 新增功能的文章,以及關於 Beta 2 新增功能的公告。
Justin Van Patten Microsoft CLR 團隊的專案經理,負責基類庫方面的工作。
相關推薦
.NET Framework 4 檔案IO讀寫的增強 激動人心的強大 或許正是你所期待的 基類庫中的新增內容 轉自msdn雜誌
CLR 全面透析 .NET Framework 4 基類庫中的新增內容 使用 Microsoft .NET 的每個人幾乎都會用到基類庫 (BCL)。一個更好的 BCL 幾乎可以惠及每一位託管程式碼開發人員。 此專欄重點介紹 .NET 4 Beta 1 在 BCL 中新增的功能。 先前的文章中已經介紹了
C#03 檔案IO,讀,寫,加密
檔案IO 檔案: 對於作業系統而言 所有東東都是一種檔案, 螢幕 鍵盤 exe程式 word 等都是檔案 咱們今天學習的檔案主要是能夠使用記事本開啟的 程式語言編寫的 .cs .c .cpp .java .js .txt .ini .bat.txt IO:
IO練習(FileReader和Writer對檔案進行讀寫)
package aa; import java.io.*; public class aaa { public static void main(String[] args) throws IOException { File file=new Fi
LinuxC程式設計之IO-通過lseek對檔案進行讀寫
1.相關API 通過lseek對檔案進行讀寫 1)open函式 int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode); 2)re
Java io 讀/寫檔案
public String inputStringFile(String filePath, String characterEncoding) throws IOException { /** * filePath --要讀取的檔案路徑 * characterEnco
使用IO進行Yaml檔案的讀寫
前言 可能是自己對yaml檔案不夠了解吧,想做一個yaml檔案的讀寫,在網上搜到的例項都是使用yaml.dump(),我也這麼跟著做,但使用該方法的yaml檔案始終在開頭有兩個!!,導致沒辦法使用yaml.load()進行讀取.最後看到一個yaml.dumpAs
Java IO讀寫大檔案的幾種方式及測試
讀取檔案大小:1.45G 第一種,OldIO: Java程式碼 publicstaticvoid oldIOReadFile() throws IOException{ BufferedReader br = new BufferedReader(new File
從零開始學C++之IO流類庫(三):檔案的讀寫、二進位制檔案的讀寫、檔案隨機讀寫
#include <cassert>#include <iostream>#include <fstream>#include <string>using namespace std;struct Test { int a; int b; };i
java IO流檔案的讀寫具體例項
IO流的分類: 1、根據流的資料物件來分: 高階流:所有的記憶體中的流都是高階流,比如:InputStreamReader 低端流:所有的外界裝置中的流都是低端流,比如InputStream,OutputStream 如何區分:所有的流物件的字尾中包含Reader或
Linux檔案IO(檔案的讀寫)
內容源於朱友鵬老師的課程筆記的學習整理,如有侵權,請告知刪除。 一、linux中如何管理檔案 (1)硬碟中的靜態檔案和iNode(i節點) 內容管理表 + 真正儲存的內容;內容管理表以檔案為單位進行管理,每個檔案一個結構體(即iNode);平常說的快速格式化,其實就是把
【Java】File類檔案管理及IO讀寫、複製操作
File類的總結: 1.檔案和資料夾的建立 2.檔案的讀取 3.檔案的寫入 4.檔案的複製(字元流、位元組流、處理流) 5.以圖片地址下載圖片 檔案和資料夾 相關函式 (boolean) mkdir() 建立此抽象路徑名指定的目錄 (boolean) mkdi
.net framework 4.0 安裝失敗解決辦法
輸入 src 更新 msvc frame redis use spa svc 方法一 1.打開cmd命令窗口 運行net stop WuAuServ 停止更新服務 2.開始----運行------輸入%windir% 3.找到SoftwareDistribut
安裝mysql提示This application requires .NET framework 4.0.
分享 clas blank 4.0 center water tar ati iss 問題描述:安裝MySQL社區版時遇到This application requires .NET framework 4.0. 解決方法:在http://search.microsoft
C# DataSet數據導入Excel 修正版- .net FrameWork 4.0以上
except 一段 tab tac office mat tar reflect line 引入 Microsoft.Office.Interop.Excel.dll 格式:標題加了下劃線,單元格內容居中 1 using System; 2 using Syst
Microsoft .NET Framework 4.5.2 (Offline Installer)
com 2012 r2 install installer frame load ram .aspx exe Microsoft .NET Framework 4.5.2 (Offline Installer) for Windows Vista SP2, Windows
IIS 安裝了.net framework 4.0/4.5 卻找不到相應應用程序池
ive framework 在哪裏 2.0 backward repl new es2017 com 通常情況下是因為沒註冊造成的,有些安裝包會自己幫你註冊上有些不會,感覺略坑。 註冊方法:在計算機中點擊 開始菜單–>運行 拷貝以下內容運行一下即可。
微軟.NET Framework 4.7.1 [32+64位]完整包,帶靜默安裝參數!
windows 相關軟件名稱:.NET Framework 4.7..1軟件大小:65.5M運行環境:vista+win7 靜默安裝參數:/quiet /norestart下載地址:https://pan.baidu.com/s/1qX8ktFQ微軟.NET Framework 4.7.1 [32+64位]完
[記錄]安裝.Net Framework 4.6.2時出現“無法建立到信任根頒發機構的證書鏈”解決方法
ctr log arr 單元 ica micode blog 下載 otc 在安裝Microsoft .NET Framework 4.6.2脫機包時提示 無法建立到信任根頒發機構的證書鏈 實際上是要安裝一個根證書。解決方案如下(因無法貼鏈接,可百度搜索“ma
WPF 實現INotifyPropertyChanged .Net Framework 4.5
hang nta not void one using style call str 自己動手寫了一個基類來實現INotifyPropertyChanged接口,以後可以直接使用。 1 using System.ComponentModel; 2
MVC .net framework 4.5 發布 瀏覽時顯示目錄
mvc 發布 瀏覽 顯示目錄問題:在IIS發布的mvc網站,瀏覽時顯示為網站目錄。 剛開始沒有註意以為mvc程序是4.0 後發現配置文件中目標框架為4.5 <system.web> <compilation targetFramework="4.5" /> <ht