Last active
September 12, 2019 19:32
-
-
Save panicoenlaxbox/2324429c276ff48ebfd90c00f7604017 to your computer and use it in GitHub Desktop.
Download file and blob in wrong and right way
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//<Project Sdk="Microsoft.NET.Sdk"> | |
// <PropertyGroup> | |
// <OutputType>Exe</OutputType> | |
// <TargetFramework>netcoreapp2.2</TargetFramework> | |
// </PropertyGroup> | |
// <ItemGroup> | |
// <PackageReference Include="CsvHelper" Version="12.1.2" /> | |
// <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.2.6" /> | |
// <PackageReference Include="TinyCsvParser" Version="2.5.2" /> | |
// <PackageReference Include="WindowsAzure.Storage" Version="9.3.3" /> | |
// <PackageReference Include="EFCore.BulkExtensions" Version="2.6.0" /> | |
// </ItemGroup> | |
//</Project> | |
using System; | |
using System.Collections.Generic; | |
using System.Diagnostics; | |
using System.IO; | |
using System.Linq; | |
using System.Net.Http; | |
using System.Text; | |
using System.Threading.Tasks; | |
using CsvHelper; | |
using CsvHelper.Configuration; | |
using EFCore.BulkExtensions; | |
using Microsoft.EntityFrameworkCore; | |
using Microsoft.WindowsAzure.Storage; | |
using Microsoft.WindowsAzure.Storage.Auth; | |
using Microsoft.WindowsAzure.Storage.Blob; | |
using TinyCsvParser; | |
using TinyCsvParser.Mapping; | |
using TinyCsvParser.TypeConverter; | |
namespace ConsoleApp3 | |
{ | |
class Program | |
{ | |
private static SyncContext CreateSyncContext() | |
{ | |
var options = new DbContextOptionsBuilder<SyncContext>() | |
.UseSqlServer(@"Server=.;Database=Sync;Trusted_Connection=True;") | |
.Options; | |
return new SyncContext(options); | |
} | |
static async Task Main(string[] args) | |
{ | |
//var url = "h"; | |
const string sasToken = ""; | |
const string accountName = ""; | |
const string containerName = ""; | |
const string blobName = ""; | |
//await HttpGetForLargeFileInWrongWay(url); | |
//await HttpGetForLargeFileInRightWay(url); | |
//await GetBlobInWrongWay(sasToken, accountName, containerName, blobName); | |
await GetBlobInRightWay(sasToken, accountName, containerName, blobName); | |
} | |
private static async Task HttpGetForLargeFileInWrongWay(string url) | |
{ | |
using (HttpClient client = new HttpClient()) | |
{ | |
using (HttpResponseMessage response = await client.GetAsync(url)) | |
using (Stream streamToReadFrom = await response.Content.ReadAsStreamAsync()) | |
{ | |
string fileToWriteTo = Path.GetTempFileName(); | |
Console.WriteLine(fileToWriteTo); | |
using (Stream streamToWriteTo = File.Open(fileToWriteTo, FileMode.Create)) | |
{ | |
await streamToReadFrom.CopyToAsync(streamToWriteTo); | |
} | |
} | |
} | |
} | |
private static async Task HttpGetForLargeFileInRightWay(string url) | |
{ | |
// http://www.tugberkugurlu.com/archive/efficiently-streaming-large-http-responses-with-httpclient | |
using (HttpClient client = new HttpClient()) | |
{ | |
using (HttpResponseMessage response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead)) | |
using (Stream streamToReadFrom = await response.Content.ReadAsStreamAsync()) | |
{ | |
string fileToWriteTo = Path.GetTempFileName(); | |
Console.WriteLine(fileToWriteTo); | |
using (Stream streamToWriteTo = File.Open(fileToWriteTo, FileMode.Create)) | |
{ | |
await streamToReadFrom.CopyToAsync(streamToWriteTo); | |
} | |
} | |
} | |
} | |
private static async Task GetBlobInWrongWay(string sasToken, string accountName, string containerName, string blobName) | |
{ | |
StorageCredentials credentials = new StorageCredentials(sasToken); | |
CloudStorageAccount account = new CloudStorageAccount(credentials, accountName, endpointSuffix: null, useHttps: true); | |
CloudBlobClient client = account.CreateCloudBlobClient(); | |
CloudBlobContainer container = client.GetContainerReference(containerName); | |
CloudBlob blob = container.GetBlobReference(blobName); | |
using (var stream = new MemoryStream()) | |
{ | |
await blob.DownloadToStreamAsync(stream); | |
IEnumerable<SyncBiDailyStock> entities = GetCsvInWrongWay(stream); | |
Console.WriteLine(entities.Count()); | |
} | |
} | |
public static async Task GetBlobInRightWay(string sasToken, string accountName, string containerName, string blobName) | |
{ | |
StorageCredentials credentials = new StorageCredentials(sasToken); | |
CloudStorageAccount account = | |
new CloudStorageAccount(credentials, accountName, endpointSuffix: null, useHttps: true); | |
CloudBlobClient client = account.CreateCloudBlobClient(); | |
CloudBlobContainer container = client.GetContainerReference(containerName); | |
CloudBlob blob = container.GetBlobReference(blobName); | |
var blockNumberOf = 1; | |
Stopwatch sw; | |
using (var context = CreateSyncContext()) | |
{ | |
await context.Database.EnsureDeletedAsync(); | |
await context.Database.EnsureCreatedAsync(); | |
sw = Stopwatch.StartNew(); | |
using (var stream = await blob.OpenReadAsync()) | |
{ | |
using (StreamReader reader = new StreamReader(stream)) | |
{ | |
var header = await reader.ReadLineAsync(); | |
var eof = false; | |
do | |
{ | |
var sw2 = Stopwatch.StartNew(); | |
var block = new StringBuilder(); | |
block.AppendLine(header); | |
var rowNumberOf = 0; | |
const int blockSize = 50000; | |
while (rowNumberOf < blockSize) | |
{ | |
var line = await reader.ReadLineAsync(); | |
if (line == null) | |
{ | |
eof = true; | |
break; | |
} | |
block.AppendLine(line); | |
rowNumberOf++; | |
} | |
using (var csvReader = new StringReader(block.ToString())) | |
{ | |
var items = GetCsvInRightWayWithCvsHelper(csvReader); | |
await context.BulkInsertAsync(items); | |
Console.WriteLine($"Block number {blockNumberOf} - {items.Count} rows - {sw2.Elapsed:g} elapsed time"); | |
blockNumberOf++; | |
} | |
//using (var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(block.ToString()))) | |
//{ | |
// var items = GetCsvInRightWayWithTinyCsvParser(memoryStream); | |
// await context.BulkInsertAsync(items); | |
// Console.WriteLine($"Block number {blockNumberOf} - {items.Count} rows - {sw2.Elapsed:g} elapsed time"); | |
// blockNumberOf++; | |
//} | |
} while (!eof); | |
} | |
} | |
} | |
Console.WriteLine(sw.Elapsed.ToString("g")); | |
} | |
public static IList<SyncBiDailyStock> GetCsvInRightWayWithCvsHelper(TextReader textReader) | |
{ | |
using (var csvReader = new CsvReader(textReader)) | |
{ | |
csvReader.Configuration.RegisterClassMap<SyncBiDailyStockMap>(); | |
csvReader.Configuration.HasHeaderRecord = true; | |
csvReader.Configuration.Delimiter = ";"; | |
return csvReader.GetRecords<SyncBiDailyStock>().ToList(); | |
} | |
} | |
public static IList<SyncBiDailyStock> GetCsvInRightWayWithTinyCsvParser(Stream stream) | |
{ | |
CsvParserOptions csvParserOptions = new CsvParserOptions(true, ';'); | |
SyncBiDailyStockMapping csvMapper = new SyncBiDailyStockMapping(); | |
CsvParser<SyncBiDailyStock> csvParser = new CsvParser<SyncBiDailyStock>(csvParserOptions, csvMapper); | |
return csvParser.ReadFromStream(stream, Encoding.UTF8).Select(r => r.Result).ToList(); | |
} | |
public static IEnumerable<SyncBiDailyStock> GetCsvInWrongWay(Stream csvStream) | |
{ | |
csvStream.Seek(0, SeekOrigin.Begin); | |
using (var reader = new StreamReader(csvStream)) | |
using (var csv = new CsvReader(reader)) | |
{ | |
csv.Configuration.RegisterClassMap<SyncBiDailyStockMap>(); | |
csv.Configuration.HasHeaderRecord = true; | |
csv.Configuration.Delimiter = ";"; | |
return csv.GetRecords<SyncBiDailyStock>().ToList(); | |
} | |
} | |
} | |
public class SyncBiDailyStock | |
{ | |
public int Id { get; set; } | |
public string PointOfSale { get; set; } | |
public string ProductCode { get; set; } | |
public DateTime Date { get; set; } | |
public int DailyStock { get; set; } | |
} | |
// CsvHelper | |
public class SyncBiDailyStockMap : ClassMap<SyncBiDailyStock> | |
{ | |
public SyncBiDailyStockMap() | |
{ | |
Map(m => m.PointOfSale).Index(1).Name("PointOfSale"); | |
Map(m => m.ProductCode).Index(0).Name("Product"); | |
Map(m => m.Date).TypeConverterOption.Format("yyyy-MM-dd").Index(2).Name("Date"); | |
Map(m => m.DailyStock).Index(3).Name("Stock"); | |
} | |
} | |
//TinyCsvParser | |
public class SyncBiDailyStockMapping : CsvMapping<SyncBiDailyStock> | |
{ | |
public SyncBiDailyStockMapping() | |
{ | |
MapProperty(0, m => m.PointOfSale); | |
MapProperty(1, m => m.ProductCode); | |
MapProperty(2, m => m.Date, new DateTimeConverter("yyyy-MM-dd")); | |
MapProperty(3, m => m.DailyStock); | |
} | |
} | |
public class SyncContext : DbContext | |
{ | |
public SyncContext(DbContextOptions<SyncContext> options) : base(options) | |
{ | |
} | |
public DbSet<SyncBiDailyStock> SyncBiDailyStocks { get; set; } | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment