Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Aplikace založené na souborech jsou programy obsažené v jednom *.cs souboru, který se sestaví a spustí bez odpovídajícího souboru projektu (*.csproj). Souborové aplikace jsou ideální pro výuku jazyka C#, protože mají menší složitost: Celý program je uložený v jednom souboru. Aplikace založené na souborech jsou také užitečné pro vytváření nástrojů příkazového řádku. Na platformách Unix lze aplikace založené na souborech spouštět pomocí #!direktiv (shebang).
V tomto kurzu se naučíte:
- Vytvořte program založený na souborech.
- Přidání podpory unixových shebangů (
#!). - Čtení argumentů příkazového řádku
- Zpracování standardního vstupu
- Napište výstup obrázku ASCII.
- Zpracování argumentů příkazového řádku
- Použijte analyzované výsledky příkazového řádku.
- Otestujte konečnou aplikaci.
Vytvoříte souborový program, který zapíše text jako obrázek ASCII. Aplikace je obsažena v jednom souboru, používá balíčky NuGet, které implementují některé základní funkce.
Požadavky
- .NET 10 SDK. Stáhněte si ho z webu pro stahování .NET.
- Visual Studio Code. Stáhněte si ji z domovské stránky editoru Visual Studio Code.
- (Volitelné) Rozšíření C# DevKit pro Visual Studio Code Stáhněte si ho z marketplace editoru Visual Studio Code.
Vytvoření programu založeného na souborech
Otevřete Visual Studio Code a vytvořte nový soubor s názvem
AsciiArt.cs. Zadejte následující text:Console.WriteLine("Hello, world!");Uložte soubor. Pak otevřete integrovaný terminál v editoru Visual Studio Code a zadejte:
dotnet run AsciiArt.cs
Při prvním spuštění tohoto programu dotnet hostitel sestaví spustitelný soubor ze zdrojového souboru, uloží artefakty sestavení do dočasné složky a potom spustí vytvořený spustitelný soubor. Toto prostředí můžete ověřit opětovným zadáním dotnet run AsciiArt.cs . Tentokrát hostitel zjistí, dotnet že spustitelný soubor je aktuální, a spustí spustitelný soubor bez jeho opětovného sestavení. Nezobrazuje se žádný výstup sestavení.
Předchozí kroky ukazují, že souborové aplikace nejsou soubory skriptů. Jedná se o zdrojové soubory jazyka C#, které jsou vytvořené pomocí vygenerovaného souboru projektu v dočasné složce. Jeden z řádků výstupu zobrazených při vytváření programu by měl vypadat přibližně takto (ve Windows):
AsciiArt succeeded (7.3s) → AppData\Local\Temp\dotnet\runfile\AsciiArt-85c58ae0cd68371711f06f297fa0d7891d0de82afde04d8c64d5f910ddc04ddc\bin\debug\AsciiArt.dll
Na platformách unix je výstupní složka podobná této:
AsciiArt succeeded (7.3s) → Library/Application Support/dotnet/runfile/AsciiArt-85c58ae0cd68371711f06f297fa0d7891d0de82afde04d8c64d5f910ddc04ddc/bin/debug/AsciiArt.dll
Tento výstup vám řekne, kam se umístí dočasné soubory a výstupy sestavení. V tomto kurzu se při každé úpravě zdrojového souboru dotnet hostitel před spuštěním aktualizuje spustitelný soubor.
Souborové aplikace jsou běžné programy jazyka C#. Jediným omezením je, že se musí zapsat do jednoho zdrojového souboru. Jako vstupní bod můžete použít příkazy nejvyšší úrovně nebo klasickou Main metodu. Můžete deklarovat libovolné typy: třídy, rozhraní a struktury. Algoritmy můžete strukturovat v programu založeném na souborech stejně jako v jakémkoli programu jazyka C#. Můžete dokonce deklarovat více oborů názvů pro uspořádání kódu. Pokud zjistíte, že se pro jeden soubor příliš rozrůstá program založený na souborech, můžete ho převést na program založený na projektu a rozdělit zdroj na více souborů. Souborové aplikace jsou skvělým nástrojem pro vytváření prototypů. Můžete začít experimentovat s minimální režií a prokázat koncepty a vytvářet algoritmy.
Podpora pro Unix shebang (#!)
Poznámka:
#! Podpora direktiv se vztahuje pouze na platformy unix. Pro Windows neexistuje podobná direktiva pro přímé spuštění programu v jazyce C#. Ve Windows musíte použít dotnet run na příkazovém řádku.
V unixu můžete spouštět aplikace založené na souborech přímo tak, že místo toho zadáte název zdrojového souboru na příkazovém dotnet runřádku . Potřebujete provést dvě změny:
Nastavte oprávnění ke spuštění zdrojového souboru:
chmod +x AsciiArt.csPřidejte direktivu shebang (
#!) jako první řádekAsciiArt.cssouboru:#!/usr/local/share/dotnet/dotnet run
Umístění dotnet se může lišit v různých instalacích unixu. Pomocí příkazu which dotnet vyhledejte dotnet hostitele ve vašem prostředí.
Alternativně můžete použít #!/usr/bin/env dotnet k automatickému určení cesty dotnet z proměnné prostředí PATH.
#!/usr/bin/env dotnet
Po provedení těchto dvou změn můžete program spustit přímo z příkazového řádku:
./AsciiArt.cs
Pokud chcete, můžete rozšíření odebrat, abyste místo toho mohli psát ./AsciiArt . Do zdrojového #! souboru můžete přidat i v případě, že používáte Windows. Příkazový řádek Windows nepodporuje #!, ale kompilátor jazyka C# umožňuje direktivu v souborových aplikacích na všech platformách.
Čtení argumentů příkazového řádku
Teď na příkazovém řádku napište všechny argumenty do výstupu.
Nahraďte aktuální obsah
AsciiArt.csnásledujícím kódem:if (args.Length > 0) { string message = string.Join(' ', args); Console.WriteLine(message); }Tuto verzi můžete spustit zadáním následujícího příkazu:
dotnet run AsciiArt.cs -- This is the command line.Tato
--možnost označuje, že všechny následující argumenty příkazů by měly být předány do programu AsciiArt. ArgumentyThis is the command line.jsou předány jako pole řetězců, kde každý řetězec je jedno slovo:This,is,the,command, aline..
Tato verze ukazuje tyto nové koncepty:
- Argumenty příkazového řádku jsou předány programu pomocí předdefinované proměnné
args. Proměnnáargsje pole řetězců:string[]. Pokud je délkaargs0, znamená to, že nebyly zadány žádné argumenty. V opačném případě je každé slovo v seznamu argumentů uloženo v odpovídající položce v poli. - Metoda
string.Joinspojí více řetězců do jednoho řetězce se zadaným oddělovačem. V tomto případě je oddělovač jedinou mezerou. - Console.WriteLine zapíše řetězec do standardní výstupní konzoly následované novým řádkem.
Zpracování standardního vstupu
Tento příkaz zpracovává správně argumenty příkazového řádku. Teď přidejte kód pro zpracování čtení vstupu ze standardního vstupu (stdin) místo argumentů příkazového řádku.
Do příkazu, který jste přidali v předchozím kódu, přidejte následující
elseklauzuliif:else { while (Console.ReadLine() is string line && line.Length > 0) { Console.WriteLine(line); } }Předchozí kód přečte vstup konzoly, dokud se nečte prázdný řádek nebo
nullpřečte. (Metoda Console.ReadLine vrátínull, pokud je vstupní datový proud zavřený zadáním ctrl+C.)Otestujte čtení standardního vstupu vytvořením nového textového souboru ve stejné složce. Pojmenujte soubor
input.txta přidejte následující řádky:Hello from ... dotnet! You can create file-based apps in .NET 10 and C# 14 Have fun writing useful utilitiesŘádky nechte krátké, aby se správně naformátovali, když přidáte funkci pro použití obrázků ASCII.
Spusťte program znovu.
S Bashem:
cat input.txt | dotnet run AsciiArt.csNebo pomocí PowerShellu:
Get-Content input.txt | dotnet run AsciiArt.cs
Teď může program přijímat argumenty příkazového řádku nebo standardní vstup.
Zápis výstupu ASCII Art
Dále přidejte balíček, který podporuje ASCII art, Colorful.Console. Pokud chcete přidat balíček do programu založeného na souborech, použijte direktivu #:package .
Do souboru AsciiArt.cs přidejte následující direktivu
#!:#:package Colorful.Console@1.2.15Důležité
1.2.15Verze byla nejnovější verzíColorful.Consolebalíčku při poslední aktualizaci tohoto kurzu. Na stránce NuGet balíčku vyhledejte nejnovější verzi a ujistěte se, že používáte verzi balíčku s nejnovějšími opravami zabezpečení.Změňte místo toho řádky, které volají
Console.WriteLinemetoduColorful.Console.WriteAscii:async Task WriteAsciiArt(AsciiMessageOptions options) { foreach (string message in options.Messages) { Colorful.Console.WriteAscii(message); await Task.Delay(options.Delay); } }Spusťte program a místo zopakovaného textu uvidíte výstup obrázku ASCII.
Možnosti příkazů procesu
Teď přidáme analýzu příkazového řádku. Aktuální verze zapisuje každé slovo jako jiný řádek výstupu. Argumenty příkazového řádku, které jste přidali, podporují dvě funkce:
Citace více slov, která by se měla napsat na jeden řádek:
AsciiArt.cs "This is line one" "This is another line" "This is the last line"--delayPřidejte mezi každý řádek možnost pozastavení:AsciiArt.cs --delay 1000
Uživatelé by měli mít možnost používat oba argumenty společně.
Většina aplikací příkazového řádku potřebuje analyzovat argumenty příkazového řádku, aby bylo možné efektivně zpracovávat možnosti, příkazy a vstupy uživatelů.
KnihovnaSystem.CommandLine poskytuje komplexní možnosti pro zpracování příkazů, dílčích příkazů, možností a argumentů, takže se můžete soustředit na to, co vaše aplikace dělá, a ne na mechaniku parsování vstupu příkazového řádku.
Knihovna System.CommandLine nabízí několik klíčových výhod:
- Automatické generování a ověřování textu nápovědy
- Podpora konvencí příkazového řádku POSIX a Windows
- Integrované možnosti dokončování tabulátoru
- Konzistentní chování analýzy napříč aplikacemi
System.CommandLinePřidejte balíček. Přidejte tuto direktivu za existující direktivu balíčku:#:package System.CommandLine@2.0.0Důležité
2.0.0Verze byla nejnovější verzí, kdy byl tento kurz naposledy aktualizován. Pokud je k dispozici novější verze, použijte nejnovější verzi, abyste měli jistotu, že máte nejnovější balíčky zabezpečení. Na stránce NuGet balíčku vyhledejte nejnovější verzi a ujistěte se, že používáte verzi balíčku s nejnovějšími opravami zabezpečení.Přidejte potřebné příkazy using v horní části souboru (za direktivy
#!a#:packagedirektivy):using System.CommandLine; using System.CommandLine.Parsing;Definujte možnost zpoždění a argument zpráv. Přidejte následující kód, který vytvoří
CommandLine.OptionobjektyCommandLine.Argument, které představují možnost a argument příkazového řádku:Option<int> delayOption = new("--delay") { Description = "Delay between lines, specified as milliseconds.", DefaultValueFactory = parseResult => 100 }; Argument<string[]> messagesArgument = new("Messages") { Description = "Text to render." };V aplikacích příkazového řádku obvykle začínají možnostmi
--(dvojitá pomlčka) a můžou přijímat argumenty. Možnost--delaypřijímá celočíselnou hodnotu, která určuje zpoždění v milisekundách. DefinujemessagesArgument, jak se všechny zbývající tokeny po parsování možností parsují jako text. Každý token se stane samostatným řetězcem v poli, ale text může obsahovat více slov v jednom tokenu. Například"This is one message"se stane jedním tokenem, zatímcoThis is four tokensse stanou čtyřmi samostatnými tokeny.Předchozí kód definuje typ argumentu
--delaypro možnost a že argumenty jsou pole hodnotstring. Tato aplikace má pouze jeden příkaz, takže použijete kořenový příkaz.Vytvořte kořenový příkaz a nakonfigurujte ho s možností a argumentem. Přidejte argument a možnost do kořenového příkazu:
RootCommand rootCommand = new("Ascii Art file-based program sample"); rootCommand.Options.Add(delayOption); rootCommand.Arguments.Add(messagesArgument);Přidejte kód pro analýzu argumentů příkazového řádku a zpracování chyb. Tento kód ověří argumenty příkazového řádku a uloží parsované argumenty v objektu System.CommandLine.ParseResult :
ParseResult result = rootCommand.Parse(args); foreach (ParseError parseError in result.Errors) { Console.Error.WriteLine(parseError.Message); } if (result.Errors.Count > 0) { return 1; }
Předchozí kód ověří všechny argumenty příkazového řádku. Pokud se ověření nezdaří, chyby se zapíšou do konzoly a aplikace se ukončí.
Použití analyzovaných výsledků příkazového řádku
Teď dokončete aplikaci, aby používala parsované možnosti a napsala výstup. Nejprve definujte záznam, který bude obsahovat parsované možnosti. Aplikace založené na souborech můžou obsahovat deklarace typů, jako jsou záznamy a třídy. Musí být po všech příkazech nejvyšší úrovně a místních funkcích.
recordPřidejte deklaraci pro uložení zpráv a hodnoty možnosti zpoždění:public record AsciiMessageOptions(string[] Messages, int Delay);Před deklaraci záznamu přidejte následující místní funkci. Tato metoda zpracovává argumenty příkazového řádku i standardní vstup a vrací novou instanci záznamu:
async Task<AsciiMessageOptions> ProcessParseResults(ParseResult result) { int delay = result.GetValue(delayOption); List<string> messages = [.. result.GetValue(messagesArgument) ?? Array.Empty<string>()]; if (messages.Count == 0) { while (Console.ReadLine() is string line && line.Length > 0) { Colorful.Console.WriteAscii(line); await Task.Delay(delay); } } return new([.. messages], delay); }Vytvořte místní funkci pro zápis artu ASCII se zadaným zpožděním. Tato funkce zapíše každou zprávu v záznamu se zadaným zpožděním mezi jednotlivými zprávami:
async Task WriteAsciiArt(AsciiMessageOptions options) { foreach (string message in options.Messages) { Colorful.Console.WriteAscii(message); await Task.Delay(options.Delay); } }Nahraďte klauzuli
if, kterou jste napsali dříve, následujícím kódem, který zpracovává argumenty příkazového řádku a zapisuje výstup:var parsedArgs = await ProcessParseResults(result); await WriteAsciiArt(parsedArgs); return 0;
Vytvořili record jste typ, který poskytuje strukturu pro parsované možnosti a argumenty příkazového řádku. Nové místní funkce vytvoří instanci záznamu a použije záznam k zápisu výstupu ASCII art.
Otestování konečné aplikace
Otestujte aplikaci spuštěním několika různých příkazů. Pokud máte potíže, tady je hotová ukázka pro porovnání s tím, co jste vytvořili:
#!/usr/local/share/dotnet/dotnet run
#:package Colorful.Console@1.2.15
#:package System.CommandLine@2.0.0
using System.CommandLine;
using System.CommandLine.Parsing;
Option<int> delayOption = new("--delay")
{
Description = "Delay between lines, specified as milliseconds.",
DefaultValueFactory = parseResult => 100
};
Argument<string[]> messagesArgument = new("Messages")
{
Description = "Text to render."
};
RootCommand rootCommand = new("Ascii Art file-based program sample");
rootCommand.Options.Add(delayOption);
rootCommand.Arguments.Add(messagesArgument);
ParseResult result = rootCommand.Parse(args);
foreach (ParseError parseError in result.Errors)
{
Console.Error.WriteLine(parseError.Message);
}
if (result.Errors.Count > 0)
{
return 1;
}
var parsedArgs = await ProcessParseResults(result);
await WriteAsciiArt(parsedArgs);
return 0;
async Task<AsciiMessageOptions> ProcessParseResults(ParseResult result)
{
int delay = result.GetValue(delayOption);
List<string> messages = [.. result.GetValue(messagesArgument) ?? Array.Empty<string>()];
if (messages.Count == 0)
{
while (Console.ReadLine() is string line && line.Length > 0)
{
// <WriteAscii>
Colorful.Console.WriteAscii(line);
// </WriteAscii>
await Task.Delay(delay);
}
}
return new([.. messages], delay);
}
async Task WriteAsciiArt(AsciiMessageOptions options)
{
foreach (string message in options.Messages)
{
Colorful.Console.WriteAscii(message);
await Task.Delay(options.Delay);
}
}
public record AsciiMessageOptions(string[] Messages, int Delay);
V tomto kurzu jste se naučili vytvořit souborový program, ve kterém program sestavíte v jednom souboru C#. Tyto programy nepoužívají soubor projektu a mohou používat direktivu #! v systémech unix. Studenti můžou tyto programy vytvářet po vyzkoušení našich online kurzů a před vytvořením větších aplikací založených na projektu. Souborové aplikace jsou také skvělou platformou pro nástroje příkazového řádku.