Pliki a tablice. Część 1

Opisywany materiał bazuje na wiadomościach podanych w temacie Okna dialogu zapisu i odczytu plików (https://www.afizyka.pl/informatyka-zapis-odczyt-plikow). W aplikacjach desktopowych pracę z plikami ułatwia okno dialogowe zapisu lub odczytu plików. W Visual Studio są to kontrolki SaveFileDialog i OpenFileDialog. Aby rozpocząć pracę z plikami należy zainicjować przestrzeń nazw System.IO.

Zmienna plikowa

W aplikacjach, które pracują z plikami przy zapisie lub odczycie należy zdefiniować zmienną reprezentującą plik w postaci strumienia danych.

W przypadku zapisu pliku jest to deklaracja o postaci

Wskazówka:


StreamWriter plik;
plik = new StreamWriter(sciezka-nazwa-pliku,false);

StreamWriter jest klasą, którą można wywołać z różnymi konfiguracjami konstruktora (więcej pod linkiem zobacz)

W przypadku odczytu danych do pliku jest to deklaracja o postaci

Wskazówka:


StreamReader plik;
plik = new StreamReader(sciezka-nazwa-pliku);

StreamReader podobnie jak w/w jest klasą, którą można wywołać w różnych konfiguracjach (patrz po linkiem zobacz)

Zapis tablic do pliku

Na przykładzie prostej aplikacji desktopowej prześledzimy mechanizm zapisu dwóch losowych tablic i jednej tablicy dwuwymiarowej. Tablice jednowymiarowe zapiszemy w wierszach, a dwuwymiarową w kolumnach. Przyjmujemy, że separatorem kolejnych wartości liczbowych będzie spacja.

Poniższa ilustracja pokazuje jak ma wyglądać plik wynikowy

pliki z zapisem tablic Visual Studio C#

Otrzymanie zapisu takiego pliku nie sprawia większych trudności. Dużo trudniej jest odczytać dane i zapisać je do tablic. Dzieje się tak, że w pliku nie podano informacji o rozmiarze tablic. Chcąc wykorzystać tablice statyczne trzeba znać ich rozmiar. Z tak podanych danych można rozmiar ustalić metodami pośrednimi. Ale o tym poniżej

Proponowany układ komponentów

W tworzonej aplikacji zastosujemy kontrolki: MenuStrip, StatusStrip, OpenFileDialog, SaveFileDialog, GroupBox, Button, Label i TextBox. Wybór opcji zadań zrealizujemy przez wykorzystani menu zapisanego w kontrolce MenuStrip. Ułożenie i zawartość kontrolek wykonaj według własnego pomysłu. Poniżej zalążek tworzonej formatki aplikacji.

aplikacja dsktopowa pliki z zapisem tablic Visual Studio C#

Tworzenie tablic

Budowanie tablic dla potrzeb tego projektu zrealizujemy przy pomocy funkcji o dwóch argumentach (rozmiar tablicy lub ilość wierszy, zakres losowych wartości). Funkcje będą zwracać utworzoną tablicę jedno lub dwuwymiarową.

Wskazówka:


Random los = new Random();

int[] BudujTablice(int w, int zakresLosowan)
{
    int[] t = new int[w];
    for (int i = 0; i < t.GetLength(0); i++) t[i] = los.Next(zakresLosowan) + 1;
    return t;
}
//przeciążenie powyższej funkcji
int[,] BudujTablice(int w,int k, int zakresLosowan)
{
    int[,] t = new int[w, k];
    for (int i = 0; i < t.GetLength(0); i++)
        for (int j = 0; j < t.GetLength(1); j++)
            t[i, j] = los.Next(zakresLosowan) + 1;
    return t;
}

Zbudowane tablice pokażemy w kontrolce TextBox przy wykorzystaniu poniższych funkcji

Wskazówka:


void PokazTablice(int[] t,TextBox tb,string naglowek)
{
    tb.AppendText(naglowek + Environment.NewLine);
    String s = "";
    for (int i = 0; i < t.GetLength(0); i++)
        s += String.Format("{0} ", t[i]);
    tb.AppendText(s + Environment.NewLine);
}
//przeciążenie powyższej funkcji
void PokazTablice(int[,] t, TextBox tb, string naglowek)
{
    tb.AppendText(naglowek + Environment.NewLine);
    for (int i = 0; i < t.GetLength(0); i++)
    {
        String s = "";
        for (int j = 0; j < t.GetLength(1); j++)
            s += String.Format("{0} ", t[i, j]);
        tb.AppendText(s + Environment.NewLine);
    }
}

Utworzone funkcje wywołamy w zdarzeniu Click kontrolki Button

Wskazówka:


private void button1_Click(object sender, EventArgs e)
{
    int n = Convert.ToInt32(textBox1.Text);
    tab1 = BudujTablice(n, 20);
    tab2 = BudujTablice(n, 50);
    n = Convert.ToInt32(textBox2.Text);
    tab2D = BudujTablice(n, 2, 50);
    PokazTablice(tab1, textBox3, "tablica tab1:");
    PokazTablice(tab2, textBox3, "tablica tab2:");
    PokazTablice(tab2D, textBox3, "tablica dwuwymiarowa tab2D:");
}

Wynik działania przedstawia poniższa ilustracja

pliki z zapisem tablic Visual Studio C#

Zapis tablic do pliku

Zapis utworzonych tablic zrealizujemy w zwykłym pliku tekstowym według wcześniej podanych warunków. Funkcję zapisującą tablice do pliku wywołamy z menu aplikacji. Poniżej spodziewany efekt podglądu zapisanego pliku z utworzonymi tablicami.

zapis tablic do pliku Visual Studio C#

Funkcje zapisu tablic do pliku utworzymy na podstawie funkcji przeciążeniowej, w których parametrami będzie strumień zapisu pliku i tablica jedno lub dwuwymiarowa. Metoda Write() i metoda WriteLine() różni się tym, że druga metoda po zapisie przechodzi do nowej linii w pliku

Wskazówka:


void ZapiszTabliceDoPliku(StreamWriter p,int[] t)
{
    int i = 0;
    //zmienna p to strumień klasy plik
    do
    {
        p.Write(String.Format("{0} ", t[i]));
        i++;
    } while (i < t.GetLength(0));
}
//przeciążenie powyższej funkcji
void ZapiszTabliceDoPliku(StreamWriter p, int[,] t)
{
    int i = 0;
    //zmienna p to strumień klasy plik
    do
    {
        //zapamietaj jeden wiersz tablicy dwuwymiarowej
        string s = "";
        for(int j=0;j<t.GetLength(1);j++)
            s+=String.Format("{0} ", t[i,j]);
        //zapisz i przejdź do nowego wiersza
        p.WriteLine(s);
        i++;
    } while (i < t.GetLength(0));
}

Wywołanie powyższych funkcji wykonamy poprzez okno dialogowe zapisu danych do pliku. Zaś wywołanie okna zapisu zrealizujemy w metodzie Click kontrolki MenuStrip

Wskazówka:


private void zapiszTabliceDoPlikuToolStripMenuItem_Click(object sender, EventArgs e)
{
    //ustaw filtr plików
    saveFileDialog1.Filter = "Pliki tekstowe .txt|*.txt|Wszystkie pliki *.*|*.*";
    //ustaw tytuł okna zapisu dialogowego
    saveFileDialog1.Title = "Zapisz zawartość";
    //narzuć filtr podstawowy
    saveFileDialog1.DefaultExt = "txt";
    if (saveFileDialog1.ShowDialog() == DialogResult.OK)
    {
        //false- nadpisze plik jak istnieje
        //true- dopisze do pliku jak istnieje
        StreamWriter plik = new StreamWriter(saveFileDialog1.FileName, false);
        ZapiszTabliceDoPliku(plik, tab1);
        plik.Write(Environment.NewLine);
        ZapiszTabliceDoPliku(plik, tab2);
        plik.Write(Environment.NewLine);
        ZapiszTabliceDoPliku(plik, tab2D);
        plik.Close();
        toolStripStatusLabel1.Text = saveFileDialog1.FileName;
    }
}

Odczyt tablic o nieznanym rozmiarze z danych zapisanych w pliku

Znając sposób zapisania danych w pliku zbudujemy tablice. Dwie będą jednowymiarowe a trzecia dwuwymiarowa. Wiemy, ze znak spacji jest separatorem wartości liczbowych. Stosując metodę String.Split podzielimy odczytane linie tekstowe pliku na mniejsze ciągi. Poniższa instrukcja realizuje taką tablicę ciągów. Argument funkcji Split jest znak separatora (tu spacja)

Wskazówka:


string[]s=linia.Split(' ');

Na podstawie otrzymanej tablicy łańcuchów ciągów ustalimy rozmiar tworzonych tablic

Wskazówka:


int[] BudujTabliceZLinii(string linia)
{
    string[]s=linia.Split(' ');
    //odejmij 1 bo ostatni znak to spacja
    int[] t = new int[s.Length-1];
    for (int j = 0; j < t.GetLength(0); j++)
        t[j] = Convert.ToInt32(s[j]);
    return t;
}
//przeciążenie powyższej funkcji
int[,] BudujTabliceZLinii(string linia1,string linia2)
{
    string[] kolumna1 = linia1.Split(' ');
    string[] kolumna2 = linia2.Split(' ');
    //odejmij 1 bo ostatni znak to spacja
    int[,] t = new int[kolumna1.Length - 1,2];
    for (int j = 0; j < t.GetLength(0); j++)
    {
        t[j, 0] = Convert.ToInt32(kolumna1[j]);
        t[j, 1] = Convert.ToInt32(kolumna2[j]);
    }
    return t;
}

Odczyt pliku danych zrealizujemy w zdarzeniu Click kolejnej opcji menu

Wskazówka:


private void pobierzTablicęZPlikuToolStripMenuItem_Click(object sender, EventArgs e)
{
    //ustaw filtr plików
    openFileDialog1.Filter = "Pliki tekstowe .txt|*.txt|Wszystkie pliki *.*|*.*";
    //ustaw tytuł okna zapisu dialogowego
    openFileDialog1.Title = "Otwórz plik";
    //narzuć filtr podstawowy
    openFileDialog1.DefaultExt = "txt";
    if (openFileDialog1.ShowDialog() == DialogResult.OK)
    {
        //buduj tablice z odczytanych linii pliku tekstowego
        StreamReader plik = new StreamReader(openFileDialog1.FileName);
        string linia="",s1="",s2="";
        int i = 0;
        while ((linia = plik.ReadLine()) != null)
        {
            if (i == 0) { 
                tab1 = BudujTabliceZLinii(linia);
                PokazTablice(tab1, textBox3, "tablica tab1 odczytana z pliku:");
            }
            if (i == 1)
            {
                tab2 = BudujTabliceZLinii(linia);
                PokazTablice(tab2, textBox3, "tablica tab2 odczytana z pliku:");
            }
            //tablicę dwuwymiarową zapisaną w kolejnych wierszach bez podania
            //poczatkowego rozmiaru zbudujemy posrednio z łancuchów znaków czytanych
            //linia po linii
            if (i > 1)
            {
                string[] s = linia.Split(' ');
                s1+= s[0]+" ";
                s2+= s[1]+" ";
            }
            i++;
        }
        plik.Close();
        //odczytałeś wszystkie linie to zbuduj tablicę dwuwymiarową
        tab2D=BudujTabliceZLinii(s1, s2);
        PokazTablice(tab2D, textBox3, "tablica dwuwymiarowa tab2D odczytana z pliku:");
        toolStripStatusLabel1.Text = openFileDialog1.FileName;
    }
}

Metoda odczytu danych nie jest już tak oczywista. Dużo łatwiej pracuje się z plikami, które zawierają informację o rozmiarze przechowywanej tablicy. Taka informacja jest namiastką pliku zdefiniowanego.

Wersja na konsolę

Powyższy problem w rozwiązaniu na konsolę wymaga wprowadzenie kilku zmian.

pliki z zapisem tablic konsola Visual Studio C#

Użyte zmienne i funkcje muszą być statyczne.

Wskazówka:


static int[] tab1, tab2;
static int[,] tab2D;
static Random los = new Random();

Przeciążenie funkcji odbywa się na tych samych zasadach co w rozwiązaniu desktopowym

Wskazówka:


static int[] BudujTablice(int w, int zakresLosowan)
{
    int[] t = new int[w];
    for (int i = 0; i < t.GetLength(0); i++) t[i] = los.Next(zakresLosowan) + 1;
    return t;
}
//przeciążenie powyższej funkcji
static int[,] BudujTablice(int w, int k, int zakresLosowan)
{
    int[,] t = new int[w, k];
    for (int i = 0; i < t.GetLength(0); i++)
        for (int j = 0; j < t.GetLength(1); j++)
            t[i, j] = los.Next(zakresLosowan) + 1;
    return t;
}

W funkcjach pokazujących zawartość tablic na ekranie konsoli rezygnujemy z argumentu TextBox, ponieważ wyniki są wysyłane na wspólny ekran konsoli. Funkcje po zmianach mają poniższą postać

Wskazówka:


static void PokazTablice(int[] t, string naglowek)
{
    Console.WriteLine(naglowek);
    String s = "";
    for (int i = 0; i < t.GetLength(0); i++)
        s += String.Format("{0} ", t[i]);
    Console.WriteLine(s);
}
//przeciążenie powyższej funkcji
static void PokazTablice(int[,] t, string naglowek)
{
    Console.WriteLine(naglowek);
    for (int i = 0; i < t.GetLength(0); i++)
    {
        String s = "";
        for (int j = 0; j < t.GetLength(1); j++)
            s += String.Format("{0} ", t[i, j]);
        Console.WriteLine(s);
    }
}

Podgląd pliku z zapisanymi danymi

W wersji konsolowej nie przewidujemy możliwości zapisania pliku pod dowolną ścieżką lokalizacji. Zakładamy, że plik wynikowy jest zapisywany w tym samym folderze co plik wykonywalny aplikacji. Z poziomu edytora kody można łatwo taki plik podglądnąć. Wybierz jak poniżej

podgląd pliku konsola Visual Studio C#

Odszukaj plik w folderze bin/Debug lub bin/Release

podgląd pliku tablic konsola Visual Studio C#

Plik po wczytaniu można porównać z ekranem konsoli

pliki z zapisem tablic konsola Visual Studio C#

Pełny kod aplikacji konsolowej

Poniżej pełny kod aplikacji konsolowej. Zauważ, że w metodzie Main() nie przewidziano menu wyboru opcji. Kod jest wykonywany linia po linii.

Wskazówka:


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace pliki_a_tablice_konsola_cz1
{
    internal class Program
    {
        static int[] tab1, tab2;
        static int[,] tab2D;
        static Random los = new Random();

        static int[] BudujTablice(int w, int zakresLosowan)
        {
            int[] t = new int[w];
            for (int i = 0; i < t.GetLength(0); i++) t[i] = los.Next(zakresLosowan) + 1;
            return t;
        }
        //przeciążenie powyższej funkcji
        static int[,] BudujTablice(int w, int k, int zakresLosowan)
        {
            int[,] t = new int[w, k];
            for (int i = 0; i < t.GetLength(0); i++)
                for (int j = 0; j < t.GetLength(1); j++)
                    t[i, j] = los.Next(zakresLosowan) + 1;
            return t;
        }

        static void PokazTablice(int[] t, string naglowek)
        {
            Console.WriteLine(naglowek);
            String s = "";
            for (int i = 0; i < t.GetLength(0); i++)
                s += String.Format("{0} ", t[i]);
            Console.WriteLine(s);
        }
        //przeciążenie powyższej funkcji
        static void PokazTablice(int[,] t, string naglowek)
        {
            Console.WriteLine(naglowek);
            for (int i = 0; i < t.GetLength(0); i++)
            {
                String s = "";
                for (int j = 0; j < t.GetLength(1); j++)
                    s += String.Format("{0} ", t[i, j]);
                Console.WriteLine(s);
            }
        }
        static void ZapiszTabliceDoPliku(StreamWriter p, int[] t)
        {
            int i = 0;
            //zmienna p to strumień klasy plik
            do
            {
                p.Write(String.Format("{0} ", t[i]));
                i++;
            } while (i < t.GetLength(0));
        }
        //przeciążenie powyższej funkcji
        static void ZapiszTabliceDoPliku(StreamWriter p, int[,] t)
        {
            int i = 0;
            //zmienna p to strumień klasy plik
            do
            {
                //zapamietaj jeden wiersz tablicy dwuwymiarowej
                string s = "";
                for (int j = 0; j < t.GetLength(1); j++)
                    s += String.Format("{0} ", t[i, j]);
                //zapisz i przejdź do nowego wiersza
                p.WriteLine(s);
                i++;
            } while (i < t.GetLength(0));
        }
        static int[] BudujTabliceZLinii(string linia)
        {
            string[] s = linia.Split(' ');
            //odejmij 1 bo ostatni znak to spacja
            int[] t = new int[s.Length - 1];
            for (int j = 0; j < t.GetLength(0); j++)
                t[j] = Convert.ToInt32(s[j]);
            return t;
        }
        //przeciążenie powyższej funkcji
        static int[,] BudujTabliceZLinii(string linia1, string linia2)
        {
            string[] kolumna1 = linia1.Split(' ');
            string[] kolumna2 = linia2.Split(' ');
            //odejmij 1 bo ostatni znak to spacja
            int[,] t = new int[kolumna1.Length - 1, 2];
            for (int j = 0; j < t.GetLength(0); j++)
            {
                t[j, 0] = Convert.ToInt32(kolumna1[j]);
                t[j, 1] = Convert.ToInt32(kolumna2[j]);
            }
            return t;
        }
        static void Main(string[] args)
        {
            Console.WriteLine("Witaj w CzD!");
            Console.WriteLine("Podaj ilość wierszy dla tablicy jednowymiarowej: ");
            int n= Convert.ToInt32(Console.ReadLine());
            tab1 = BudujTablice(n, 20);
            tab2 = BudujTablice(n, 50);
            PokazTablice(tab1,"tablica tab1:");
            PokazTablice(tab2,"tablica tab2:");
            Console.WriteLine("Podaj ilość wierszy dla tablicy dwuwymiarowej: ");
            n = Convert.ToInt32(Console.ReadLine());
            tab2D = BudujTablice(n, 2, 50);
            PokazTablice(tab2D,"tablica dwuwymiarowa tab2D:");
            Console.WriteLine("*****ZAPIS DO PLIKU dane.txt*****");
            //false- nadpisze plik jak istnieje
            //true- dopisze do pliku jak istnieje
            StreamWriter plik = new StreamWriter("dane.txt", false);
            ZapiszTabliceDoPliku(plik, tab1);
            plik.Write(Environment.NewLine);
            ZapiszTabliceDoPliku(plik, tab2);
            plik.Write(Environment.NewLine);
            ZapiszTabliceDoPliku(plik, tab2D);
            plik.Close();
            Console.WriteLine("*****ODCZYT PLIKU dane.txt DO EKRANU KONSOLI*****");
            StreamReader plikDoKonsoli = new StreamReader("dane.txt");
            //wczytaj plik do ekranu konsoli
            Console.Write(plikDoKonsoli.ReadToEnd());
            plikDoKonsoli.Close();
            Console.WriteLine("*****ODCZYT PLIKU dane.txt DO TABLIC*****");
            StreamReader plikDoTablic = new StreamReader("dane.txt");
            string linia = "", s1 = "", s2 = "";
            int i = 0;
            while ((linia = plikDoTablic.ReadLine()) != null)
            {
                if (i == 0)
                {
                    tab1 = BudujTabliceZLinii(linia);
                    PokazTablice(tab1, "tablica tab1 odczytana z pliku:");
                }
                if (i == 1)
                {
                    tab2 = BudujTabliceZLinii(linia);
                    PokazTablice(tab2, "tablica tab2 odczytana z pliku:");
                }
                //tablicę dwuwymiarową zapisaną w kolejnych wierszach bez podania
                //poczatkowego rozmiaru zbudujemy posrednio z łancuchów znaków czytanych
                //linia po linii
                if (i > 1)
                {
                    string[] s = linia.Split(' ');
                    s1 += s[0] + " ";
                    s2 += s[1] + " ";
                }
                i++;
            }
            plikDoTablic.Close();
            //odczytałeś wszystkie linie to zbuduj tablicę dwuwymiarową
            tab2D = BudujTabliceZLinii(s1, s2);
            PokazTablice(tab2D,"tablica dwuwymiarowa tab2D odczytana z pliku:");
            Console.ReadKey();
        }
    }
}

Pełny kod aplikacji desktopowej

Poniżej pełny kod aplikacji

Wskazówka:


using System;
using System.Windows.Forms;
using System.IO;


namespace pliki_a_tablice
{
    public partial class Form1 : Form
    {
        int[] tab1, tab2;
        int[,] tab2D;
        Random los = new Random();

        int[] BudujTablice(int w, int zakresLosowan)
        {
            int[] t = new int[w];
            for (int i = 0; i < t.GetLength(0); i++) t[i] = los.Next(zakresLosowan) + 1;
            return t;
        }
        //przeciążenie powyższej funkcji
        int[,] BudujTablice(int w,int k, int zakresLosowan)
        {
            int[,] t = new int[w, k];
            for (int i = 0; i < t.GetLength(0); i++)
                for (int j = 0; j < t.GetLength(1); j++)
                    t[i, j] = los.Next(zakresLosowan) + 1;
            return t;
        }

        void PokazTablice(int[] t,TextBox tb,string naglowek)
        {
            tb.AppendText(naglowek + Environment.NewLine);
            String s = "";
            for (int i = 0; i < t.GetLength(0); i++)
                s += String.Format("{0} ", t[i]);
            tb.AppendText(s + Environment.NewLine);
        }
        //przeciążenie powyższej funkcji
        void PokazTablice(int[,] t, TextBox tb, string naglowek)
        {
            tb.AppendText(naglowek + Environment.NewLine);
            for (int i = 0; i < t.GetLength(0); i++)
            {
                String s = "";
                for (int j = 0; j < t.GetLength(1); j++)
                    s += String.Format("{0} ", t[i, j]);
                tb.AppendText(s + Environment.NewLine);
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            int n = Convert.ToInt32(textBox1.Text);
            tab1 = BudujTablice(n, 20);
            tab2 = BudujTablice(n, 50);
            n = Convert.ToInt32(textBox2.Text);
            tab2D = BudujTablice(n, 2, 50);
            PokazTablice(tab1, textBox3, "tablica tab1:");
            PokazTablice(tab2, textBox3, "tablica tab2:");
            PokazTablice(tab2D, textBox3, "tablica dwuwymiarowa tab2D:");
        }

        void ZapiszTabliceDoPliku(StreamWriter p,int[] t)
        {
            int i = 0;
            //zmienna p to strumień klasy plik
            do
            {
                p.Write(String.Format("{0} ", t[i]));
                i++;
            } while (i < t.GetLength(0));
        }
        //przeciążenie powyższej funkcji
        void ZapiszTabliceDoPliku(StreamWriter p, int[,] t)
        {
            int i = 0;
            //zmienna p to strumień klasy plik
            do
            {
                //zapamietaj jeden wiersz tablicy dwuwymiarowej
                string s = "";
                for(int j=0;j<t.GetLength(1);j++)
                   s+=String.Format("{0} ", t[i,j]);
                //zapisz i przejdź do nowego wiersza
                p.WriteLine(s);
                i++;
            } while (i < t.GetLength(0));
        }
int[] BudujTabliceZLinii(string linia)
{
    string[]s=linia.Split(' ');
    //odejmij 1 bo ostatni znak to spacja
    int[] t = new int[s.Length-1];
    for (int j = 0; j < t.GetLength(0); j++)
        t[j] = Convert.ToInt32(s[j]);
    return t;
}
//przeciążenie powyższej funkcji
int[,] BudujTabliceZLinii(string linia1,string linia2)
{
    string[] kolumna1 = linia1.Split(' ');
    string[] kolumna2 = linia2.Split(' ');
    //odejmij 1 bo ostatni znak to spacja
    int[,] t = new int[kolumna1.Length - 1,2];
    for (int j = 0; j < t.GetLength(0); j++)
    {
        t[j, 0] = Convert.ToInt32(kolumna1[j]);
        t[j, 1] = Convert.ToInt32(kolumna2[j]);
    }
    return t;
}

        private void zapiszTabliceDoPlikuToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //ustaw filtr plików
            saveFileDialog1.Filter = "Pliki tekstowe .txt|*.txt|Wszystkie pliki *.*|*.*";
            //ustaw tytuł okna zapisu dialogowego
            saveFileDialog1.Title = "Zapisz zawartość";
            //narzuć filtr podstawowy
            saveFileDialog1.DefaultExt = "txt";
            if (saveFileDialog1.ShowDialog() == DialogResult.OK)
            {
                //false- nadpisze plik jak istnieje
                //true- dopisze do pliku jak istnieje
                StreamWriter plik = new StreamWriter(saveFileDialog1.FileName, false);
                ZapiszTabliceDoPliku(plik, tab1);
                plik.Write(Environment.NewLine);
                ZapiszTabliceDoPliku(plik, tab2);
                plik.Write(Environment.NewLine);
                ZapiszTabliceDoPliku(plik, tab2D);
                plik.Close();
                toolStripStatusLabel1.Text = saveFileDialog1.FileName;
            }
        }

        private void pobierzTablicęZPlikuToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //ustaw filtr plików
            openFileDialog1.Filter = "Pliki tekstowe .txt|*.txt|Wszystkie pliki *.*|*.*";
            //ustaw tytuł okna zapisu dialogowego
            openFileDialog1.Title = "Otwórz plik";
            //narzuć filtr podstawowy
            openFileDialog1.DefaultExt = "txt";
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                //buduj tablice z odczytanych linii pliku tekstowego
                StreamReader plik = new StreamReader(openFileDialog1.FileName);
                string linia="",s1="",s2="";
                int i = 0;
                while ((linia = plik.ReadLine()) != null)
                {
                    if (i == 0) { 
                        tab1 = BudujTabliceZLinii(linia);
                        PokazTablice(tab1, textBox3, "tablica tab1 odczytana z pliku:");
                    }
                    if (i == 1)
                    {
                        tab2 = BudujTabliceZLinii(linia);
                        PokazTablice(tab2, textBox3, "tablica tab2 odczytana z pliku:");
                    }
                    //tablicę dwuwymiarową zapisaną w kolejnych wierszach bez podania
                    //poczatkowego rozmiaru zbudujemy posrednio z łancuchów znaków czytanych
                    //linia po linii
                    if (i > 1)
                    {
                        string[] s = linia.Split(' ');
                        s1+= s[0]+" ";
                        s2+= s[1]+" ";
                    }
                    i++;
                }
                plik.Close();
                //odczytałeś wszystkie linie to zbuduj tablicę dwuwymiarową
                tab2D=BudujTabliceZLinii(s1, s2);
                PokazTablice(tab2D, textBox3, "tablica dwuwymiarowa tab2D odczytana z pliku:");
                toolStripStatusLabel1.Text = openFileDialog1.FileName;
            }
        }

        public Form1()
        {
            InitializeComponent();
        }

        
    }
}
Układ okresowy- kod qr
Układ okresowy

Układ okresowy pierwiastków- darmowa aplikacja na Androida

Pobierz ze sklepu Google Play
Alkomat- wirtualny test kod qr
Alkomat- wirtualny test

Alkomat- darmowa aplikacja na Androida

Pobierz ze sklepu Google Play
Taklarz- olinowanie stałe kod qr
Olinowanie stałe- kalkulator średnic

Olinowanie stałe- darmowa aplikacja na Androida

Pobierz ze sklepu Google Play
przepis na gogfry

Przepis na gofry

zobacz
przepis na bitą śmietanę

Przepis na bitą śmietanę

zobacz