StreamWriter与FileStream的关闭

麻城BriceWu 2016-06-01 10:52:55
StreamWriter sw =File.CreateText(path);
//写入
sw.Close();


当我们创建一个StreamWriter,使用完成后,直接关闭即可。
但当我们先创建一个FileStream,在此基础上再创建一个StreamWriter,却需要先关闭StreamWriter,再关闭FileStream,如下:
FileStream fs = File.Open(path, FileMode.OpenOrCreate);
StreamWriter sw1 = new StreamWriter(fs);
//写入
sw1.Close();
fs.Close();


第二种方法需要先打开文件,再进行写操作。再关闭写的流,然后关闭文件流。
而第一种方法只需要关闭写的流,难道它不需要打开和关闭文件吗?
...全文
997 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
StreamWriter 执行 Close 的时候就会去执行 Dispose,而执行 Dispose 的时候就会去执行 Flush 并且再将当初做为参数的 stream 也给 Close 了。但是为了简单,我们通常写
using(FileStream fs = File.Open(path, FileMode.OpenOrCreate))
using(StreamWriter sw1 = new StreamWriter(fs))
{
    ....... 使用 sw1 的操作
};
这可以确保调用 Dispose。不用调用 Close,调用 dispose 就够了。 如果不写,显然 GC 回收 StreamWriter 对象时也会调用 Dispose 的,也会去 Flush 和 Close。但是那就有几秒钟延迟,而这个时候可能就会造成应用中某些地方的使用这些资源的代码抛出运行异常。 而如果你显示地去使用 using{ } 来调用 Dispose,从上面贴出的源代码看,它调用了 GC.SuppressFinalize((object) this),也就是说在 GC 回收 StreamWriter 对象时就不会额外去再调用 Close 方法了。
Poopaye 2016-06-01
  • 打赏
  • 举报
回复
第二种你关闭fs都是多余的,请阅读StreamWriter.Close的作用 https://msdn.microsoft.com/zh-cn/library/system.io.streamwriter.close%28v=vs.80%29.aspx
  • 打赏
  • 举报
回复
是的!应该通过看源代码来学习 .net。许多时候,源代码跟自己推理、眼睛看到的都有差别。 写 fs.Close() 其实是多余的写法,只不过不会报错而已。大多数人都会有担心,所以写它也无妨,.net 也支持你多余地写 fs.Close()。然而从原理上看,StreamWriter 在 Close 时会额外地去调用 stream 的 Close方法。
songbing774933 2016-06-01
  • 打赏
  • 举报
回复
部分关键代码:

internal StreamWriter(string path, bool append, Encoding encoding, int bufferSize, bool checkHost)
: base((IFormatProvider) null)
{
if (path == null)
throw new ArgumentNullException("path");
if (encoding == null)
throw new ArgumentNullException("encoding");
if (path.Length == 0)
throw new ArgumentException(Environment.GetResourceString("Argument_EmptyPath"));
if (bufferSize <= 0)
throw new ArgumentOutOfRangeException("bufferSize", Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
this.Init(StreamWriter.CreateFile(path, append, checkHost), encoding, bufferSize, false);
}

/// <summary>
/// 用指定的编码及默认缓冲区大小,为指定的流初始化 <see cref="T:System.IO.StreamWriter"/> 类的新实例,有选择性的打开流。
/// </summary>
/// <param name="stream">要写入的流。</param><param name="encoding">要使用的字符编码。</param><param name="bufferSize">缓冲区大小(以字节为单位)。</param><param name="leaveOpen">如果在释放 <see cref="T:System.IO.StreamWriter"/> 对象之后打开流对象,则为 true;否则为, false。</param><exception cref="T:System.ArgumentNullException"><paramref name="stream"/> 或 <paramref name="encoding"/> 为 null。</exception><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="bufferSize"/> 为负。</exception><exception cref="T:System.ArgumentException"><paramref name="stream"/> 不可写。</exception>
[__DynamicallyInvokable]
public StreamWriter(Stream stream, Encoding encoding, int bufferSize, bool leaveOpen)
: base((IFormatProvider) null)
{
if (stream == null || encoding == null)
throw new ArgumentNullException(stream == null ? "stream" : "encoding");
if (!stream.CanWrite)
throw new ArgumentException(Environment.GetResourceString("Argument_StreamNotWritable"));
if (bufferSize <= 0)
throw new ArgumentOutOfRangeException("bufferSize", Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
this.Init(stream, encoding, bufferSize, leaveOpen);
}

/// <summary>
/// 关闭当前的 StreamWriter 对象和基础流。
/// </summary>
/// <exception cref="T:System.Text.EncoderFallbackException">当前编码不支持显示半个 Unicode 代理项对。</exception><filterpriority>1</filterpriority>
public override void Close()
{
this.Dispose(true);
GC.SuppressFinalize((object) this);
}

/// <summary>
/// 释放由 <see cref="T:System.IO.StreamWriter"/> 占用的非托管资源,还可以另外再释放托管资源。
/// </summary>
/// <param name="disposing">true 表示释放托管资源和非托管资源;false 表示仅释放非托管资源。</param><exception cref="T:System.Text.EncoderFallbackException">当前编码不支持显示半个 Unicode 代理项对。</exception>
[__DynamicallyInvokable]
protected override void Dispose(bool disposing)
{
try
{
if (this.stream == null || !disposing && (!this.LeaveOpen || !(this.stream is __ConsoleStream)))
return;
this.CheckAsyncTaskInProgress();
this.Flush(true, true);
if (this.mdaHelper == null)
return;
GC.SuppressFinalize((object) this.mdaHelper);
}
finally
{
if (!this.LeaveOpen)
{
if (this.stream != null)
{
try
{
if (disposing)
this.stream.Close();
}
finally
{
this.stream = (Stream) null;
this.byteBuffer = (byte[]) null;
this.charBuffer = (char[]) null;
this.encoding = (Encoding) null;
this.encoder = (Encoder) null;
this.charLen = 0;
base.Dispose(disposing);
}
}
}
}
}
songbing774933 2016-06-01
  • 打赏
  • 举报
回复
在StreamWriter类中包含一个私有的Stream,
如果你使用public StreamWriter(string path);这个构造函数,StreamWriter会主动创建一个FileStream
如果你使用public StreamWriter(Stream stream);这个构造函数,StreamWriter则不会再创建FileStream而是直接使用你传入的Stream 。

其次,无论你是使用的哪个构造函数,StreamWriter在Close的时候都会关闭FileStream。
你可以尝试如下代码:
FileStream fs = new FileStream(@"D:\test.txt" , FileMode.OpenOrCreate);
StreamWriter sw = new StreamWriter(fs);

sw.Close( );
fs.Close( );
在 sw.Close( );执行完毕后,其实fs已经被关闭了。因此 fs.Close( );其实是可以省略的。
当然,这样的写法不会有任何问题,因为Dispose不会被执行两次。

但是, sw.Close( );
fs.Close( );
这两行代码不可以交换顺序,如果先执行 fs.Close( );再执行 sw.Close( );将引发异常。
因为在StreamWriter的Close函数调用过程中,将调用Flush函数,而此时fs已经被关闭,Flush将产生异常。


如果想详细了解,可以查看StreamWriter的源代码。

其实,在这种多重复用关系的对象中,都要遵循一个先创建,后关闭的原则。即先进后出,后进先出。就像栈一样。
  • 打赏
  • 举报
回复
首先这两种方法的Close函数是不一样的。StreamWriter 并不是Stream的子类,它是一个封装好的类,功能是向流里面写入字符。 因此它的close方法和Stream类是不一样的,当调用它的close函数的时候,它会是否自己占用的所有资源,包括流,所以。 而第二种,则是关闭实例化了的Stream子类,也就是你说的关闭流。
crystal_lz 2016-06-01
  • 打赏
  • 举报
回复

所以说fs关闭后 sw1 并没有什么卵用
其实流也就只有一个而已 不是因为你创建了多少个类 就有多少个流
sw1 只是继承的fs 的流而已 所以fs关闭后 sw1就没有什么卵用了
而且我一般也不使用你后面这种写法 看着别扭

using(StreamReader reader = new StreamReader(path,Encoding.UTF8)){

}
xdashewan 2016-06-01
  • 打赏
  • 举报
回复
第2种方式是用流去创建流,按照微软示例只需要关闭后者即可,但一般谨慎起见会加上前者的关闭,打开关闭成对也便于代码阅读。 msdn示例:https://msdn.microsoft.com/zh-cn/library/wtbhzte9(v=vs.80).aspx
//写入文件 private void btnWriteAll_Click(object sender, EventArgs e) { if (this.txtcreatefile.Text.Length == 0) { MessageBox.Show("路径不能为空!", "信息提示"); this.txtcreatefile.Focus(); } else { if (File.Exists(this.txtcreatefile.Text.Trim()) == true) { DialogResult result = MessageBox.Show("该路径下已经存在相同文件,是否覆盖源文件?", "信息提示", MessageBoxButtons.OKCancel); if (result == DialogResult.OK) { //创建文件流 FileStream fs = new FileStream(this.txtcreatefile.Text.Trim(), FileMode.Create); //创建写入器 StreamWriter sw = new StreamWriter(fs); //开始写入文件内容 sw.Write(this.txtContent.Text.Trim() + "\r\n"); //sw.WriteLine(); //关闭写入器 sw.Close(); //关闭文件流 fs.Close(); MessageBox.Show("文件创建成功!"); } else return; } else { //创建文件流 FileStream fs = new FileStream(this.txtcreatefile.Text.Trim(), FileMode.Create); //创建写入器 StreamWriter sw = new StreamWriter(fs); //开始写入文件内容 sw.Write(this.txtContent.Text.Trim() + "\r\n"); //sw.WriteLine(); //关闭写入器 sw.Close(); //关闭文件流 fs.Close(); MessageBox.Show("文件创建成功!"); } } } private void btnReadAll_Click(object sender, EventArgs e) { if (this.txtcreatefile.Text.Length == 0) { MessageBox.Show("路径不能为空!", "信息提示"); this.txtcreatefile.Focus(); } else { //创建文件流 FileStream fs = new FileStream(this.txtcreatefile.Text.Trim(), FileMode.Open); //创建读取器 StreamReader sr = new StreamReader(fs); //开始读取 this.txtContent.Text = sr.ReadToEnd();//丛当前文件开头读到末尾 //关闭读取器 sr.Close(); //关闭文件流 fs.Close(); } } private void btnWriteLine_Click(object sender, EventArgs e) { if (this.txtcreatefile.Text.Length == 0) { MessageBox.Show("路径不能为空!", "信息提示"); this.txtcreatefile.Focus(); } else { //创建文件流 FileStream fs = new FileStream(this.txtcreatefile.Text.Trim(), FileMode.Append); //创建写入器 StreamWriter sw = new StreamWriter(fs); //开始写入 sw.WriteLine(DateTime.Now.ToString() + this.txtContent.Text.Trim()); //关闭写入器 sw.Close(); //关闭文件流 fs.Close(); } } .........
用VS编写的FTP服务器软件,C#网络程序编程学习用。 代码: using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Net; using System.Net.Sockets; using System.Threading; using System.Windows.Forms; namespace FtpServer { public partial class FtpServerForm : Form { TcpListener myTcpListener = null; private Thread listenThread; // 保存用户名和密码 Dictionary users; public FtpServerForm() { InitializeComponent(); // 初始化用户名和密码 users = new Dictionary(); users.Add("admin", "admin"); // 设置默认的主目录 tbxFtpRoot.Text = "F:/MyFtpServerRoot/"; IPAddress[] ips = Dns.GetHostAddresses(""); tbxFtpServerIp.Text = ips[5].ToString(); tbxFtpServerPort.Text = "21"; lstboxStatus.Enabled = false; } // 启动服务器 private void btnFtpServerStartStop_Click(object sender, EventArgs e) { if (myTcpListener == null) { listenThread = new Thread(ListenClientConnect); listenThread.IsBackground = true; listenThread.Start(); lstboxStatus.Enabled = true; lstboxStatus.Items.Clear(); lstboxStatus.Items.Add("已经启动Ftp服务..."); btnFtpServerStartStop.Text = "停止"; } else { myTcpListener.Stop(); myTcpListener = null; listenThread.Abort(); lstboxStatus.Items.Add("Ftp服务已停止!"); lstboxStatus.TopIndex = lstboxStatus.Items.Count - 1; btnFtpServerStartStop.Text = "启动"; } } // 监听端口,处理客户端连接 private void ListenClientConnect() { myTcpListener = new TcpListener(IPAddress.Parse(tbxFtpServerIp.Text), int.Parse(tbxFtpServerPort.Text)); // 开始监听传入的请求 myTcpListener.Start(); AddInfo("启动FTP服务成功!"); AddInfo("Ftp服务器运行中...[点击”停止“按钮停止FTP服务]"); while (true) { try { // 接收连接请求 TcpClient tcpClient = myTcpListener.AcceptTcpClient(); AddInfo(string.Format("客户端({0})与本机({1})建立Ftp连接", tcpClient.Client.RemoteEndPoint, myTcpListener.LocalEndpoint)); User user = new User(); user.commandSession = new UserSeesion(tcpClient); user.workDir = tbxFtpRoot.Text; Thread t = new Thread(UserProcessing); t.IsBackground = true; t.Start(user); } catch { break; } } } // 处理客户端用户请求 private void UserProcessing(object obj) { User user = (User)obj; string sendString = "220 FTP Server v1.0"; RepleyCommandToUser(user, sendString); while (true) { string receiveString = null; try { // 读取客户端发来的请求信息 receiveString = user.commandSession.streamReader.ReadLine(); } catch(Exception ex) { if (user.commandSession.tcpClient.Connected == false) { AddInfo(string.Format("客户端({0}断开连接!)", user.commandSession.tcpClient.Client.RemoteEndPoint)); } else { AddInfo("接收命令失败!" + ex.Message); } break; } if (receiveString == null) { AddInfo("接收字符串为null,结束线程!"); break; } AddInfo(string.Format("来自{0}:[{1}]", user.commandSession.tcpClient.Client.RemoteEndPoint, receiveString)); // 分解客户端发来的控制信息中的命令和参数 string command = receiveString; string param = string.Empty; int index = receiveString.IndexOf(' '); if (index != -1) { command = receiveString.Substring(0, index).ToUpper(); param = receiveString.Substring(command.Length).Trim(); } // 处理不需登录即可响应的命令(这里只处理QUIT) if (command == "QUIT") { // 关闭TCP连接并释放与其关联的所有资源 user.commandSession.Close(); return; } else { switch (user.loginOK) { // 等待用户输入用户名: case 0: CommandUser(user, command, param); break; // 等待用户输入密码 case 1: CommandPassword(user, command, param); break; // 用户名和密码验证正确后登陆 case 2: switch (command) { case "CWD": CommandCWD(user, param); break; case "PWD": CommandPWD(user); break; case "PASV": CommandPASV(user); break; case "PORT": CommandPORT(user, param); break; case "LIST": CommandLIST(user, param); break; case "NLIST": CommandLIST(user, param); break; // 处理下载文件命令 case "RETR": CommandRETR(user, param); break; // 处理上传文件命令 case "STOR": CommandSTOR(user, param); break; // 处理删除命令 case "DELE": CommandDELE(user, param); break; // 使用Type命令在ASCII和二进制模式进行变换 case "TYPE": CommandTYPE(user, param); break; default: sendString = "502 command is not implemented."; RepleyCommandToUser(user, sendString); break; } break; } } } } // 想客户端返回响应码 private void RepleyCommandToUser(User user, string str) { try { user.commandSession.streamWriter.WriteLine(str); AddInfo(string.Format("向客户端({0})发送[{1}]", user.commandSession.tcpClient.Client.RemoteEndPoint, str)); } catch { AddInfo(string.Format("向客户端({0})发送信息失败", user.commandSession.tcpClient.Client.RemoteEndPoint)); } } // 向屏幕输出显示状态信息(这里使用了委托机制) private delegate void AddInfoDelegate(string str); private void AddInfo(string str) { // 如果调用AddInfo()方法的线程与创建ListView控件的线程不在一个线程时 // 此时利用委托在创建ListView的线程上调用 if (lstboxStatus.InvokeRequired == true) { AddInfoDelegate d = new AddInfoDelegate(AddInfo); this.Invoke(d, str); } else { lstboxStatus.Items.Add(str); lstboxStatus.TopIndex = lstboxStatus.Items.Count - 1; lstboxStatus.ClearSelected(); } } #region 处理各个命令 #region 登录过程,即用户身份验证过程 // 处理USER命令,接收用户名但不进行验证 private void CommandUser(User user, string command, string param) { string sendString = string.Empty; if (command == "USER") { sendString = "331 USER command OK, password required."; user.userName = param; // 设置loginOk=1为了确保后面紧接的要求输入密码 // 1表示已接收到用户名,等到接收密码 user.loginOK = 1; } else { sendString = "501 USER command syntax error."; } RepleyCommandToUser(user, sendString); } // 处理PASS命令,验证用户名和密码 private void CommandPassword(User user, string command, string param) { string sendString = string.Empty; if (command == "PASS") { string password = null; if (users.TryGetValue(user.userName, out password)) { if (password == param) { sendString = "230 User logged in success"; // 2表示登录成功 user.loginOK = 2; } else { sendString = "530 Password incorrect."; } } else { sendString = "530 User name or password incorrect."; } } else { sendString = "501 PASS command Syntax error."; } RepleyCommandToUser(user, sendString); // 用户当前工作目录 user.currentDir = user.workDir; } #endregion #region 文件管理命令 // 处理CWD命令,改变工作目录 private void CommandCWD(User user, string temp) { string sendString = string.Empty; try { string dir = user.workDir.TrimEnd('/') + temp; // 是否为当前目录的子目录,且不包含父目录名称 if (Directory.Exists(dir)) { user.currentDir = dir; sendString = "250 Directory changed to '" + dir + "' successfully"; } else { sendString = "550 Directory '" + dir + "' does not exist"; } } catch { sendString = "502 Directory changed unsuccessfully"; } RepleyCommandToUser(user,sendString); } // 处理PWD命令,显示工作目录 private void CommandPWD(User user) { string sendString = string.Empty; sendString = "257 '" + user.currentDir + "' is the current directory"; RepleyCommandToUser(user, sendString); } // 处理LIST/NLIST命令,想客户端发送当前或指定目录下的所有文件名和子目录名 private void CommandLIST(User user, string parameter) { string sendString = string.Empty; DateTimeFormatInfo dateTimeFormat = new CultureInfo("en-US", true).DateTimeFormat; // 得到目录列表 string[] dir = Directory.GetDirectories(user.currentDir); if (string.IsNullOrEmpty(parameter) == false) { if (Directory.Exists(user.currentDir + parameter)) { dir = Directory.GetDirectories(user.currentDir + parameter); } else { string s = user.currentDir.TrimEnd('/'); user.currentDir = s.Substring(0, s.LastIndexOf("/") + 1); } } for (int i = 0; i < dir.Length; i++) { string folderName = Path.GetFileName(dir[i]); DirectoryInfo d = new DirectoryInfo(dir[i]); // 按下面的格式输出目录列表 sendString += @"dwr-\t" + Dns.GetHostName() + "\t" + dateTimeFormat.GetAbbreviatedMonthName(d.CreationTime.Month) + d.CreationTime.ToString(" dd yyyy") + "\t" + folderName + Environment.NewLine; } // 得到文件列表 string[] files = Directory.GetFiles(user.currentDir); if (string.IsNullOrEmpty(parameter) == false) { if (Directory.Exists(user.currentDir + parameter + "/")) { files = Directory.GetFiles(user.currentDir + parameter + "/"); } } for (int i = 0; i 1024的随机端口 // 下面这个运算算法只是为了得到一个大于1024的端口值 port = random1 << 8 | random2; try { user.dataListener = new TcpListener(localip, port); AddInfo("TCP 数据连接已打开(被动模式)--" + localip.ToString() + ":" + port); } catch { continue; } user.isPassive = true; string temp = localip.ToString().Replace('.', ','); // 必须把端口号IP地址告诉客户端,客户端接收到响应命令后, // 再通过新的端口连接服务器的端口P,然后进行文件数据传输 sendString = "227 Entering Passive Mode(" + temp + "," + random1 + "," + random2 + ")"; RepleyCommandToUser(user, sendString); user.dataListener.Start(); break; } } // 处理PORT命令,使用主动模式进行传输 private void CommandPORT(User user, string portstring) { // 主动模式时,客户端必须告知服务器接收数据的端口号,PORT 命令格式为:PORT address // address参数的格式为i1、i2、i3、i4、p1、p2,其中i1、i2、i3、i4表示IP地址 // 下面通过.字符串来组合这四个参数得到IP地址 // p1、p2表示端口号,下面通过int.Parse(temp[4]) << 8) | int.Parse(temp[5] // 这个算法来获得一个大于1024的端口来发送给服务器 string sendString = string.Empty; string[] temp = portstring.Split(','); string ipString = "" + temp[0] + "." + temp[1] + "." + temp[2] + "." + temp[3]; // 客户端发出PORT命令把客户端的IP地址和随机的端口告诉服务器 int portNum = (int.Parse(temp[4]) < 0) { user.dataSession.binaryWriter.Write(bytes, 0, count); user.dataSession.binaryWriter.Flush(); count = binaryReader.Read(bytes, 0, bytes.Length); } } else { StreamReader streamReader = new StreamReader(fs); while (streamReader.Peek() > -1) { user.dataSession.streamWriter.WriteLine(streamReader.ReadLine()); } } AddInfo("...]发送完毕!"); } finally { user.dataSession.Close(); fs.Close(); } } // 使用数据连接接收文件流(客户端发送上传文件功能) private void ReadFileByUserSession(User user, FileStream fs) { AddInfo("接收用户上传数据(文件流):[..."); try { if (user.isBinary) { byte[] bytes = new byte[1024]; BinaryWriter binaryWriter = new BinaryWriter(fs); int count = user.dataSession.binaryReader.Read(bytes, 0, bytes.Length); while (count > 0) { binaryWriter.Write(bytes, 0, count); binaryWriter.Flush(); count = user.dataSession.binaryReader.Read(bytes, 0, bytes.Length); } } else { StreamWriter streamWriter = new StreamWriter(fs); while (user.dataSession.streamReader.Peek() > -1) { streamWriter.Write(user.dataSession.streamReader.ReadLine()); streamWriter.Flush(); } } AddInfo("...]接收完毕"); } finally { user.dataSession.Close(); fs.Close(); } } private void label3_Click(object sender, EventArgs e) { } } }
总结: 1、关于C#的知识 (1)、文件输入输出—数据流 1、FileStream类 例子: SqlDataReader reader = job.WriteFileToTxt(); FileStream jobStream = new FileStream(@fileName,FileMode.Open,FileAccess.ReadWrite);//覆盖 //FileStream jobStream = new FileStream(@fileName, FileMode.Append, FileAccess.Write);//追加 StreamWriter streamw = new StreamWriter(jobStream); string outfiles = null; streamw.WriteLine("此次任务信息如下:"); streamw.WriteLine("outfiles");//读取完毕后换行 reader.Close(); streamw.Close(); jobStream.Close(); 数据流一定要用try/catch语句块包起来,同时,例子中的fileName是文件路径,如果是*.txt之类的则默认存储在程序 的文件夹下 FileMode有很多枚举成员,其中 1)Append是打开现有文件或者创建新文件,其只能和FileAccess.Write一起使用; 2)Create是如果文件不存在,则使用CreateNew,否则使用Truncate,其要求FileIOPermissionAccess.Write; 3)CreateNew创建新文件,要求FileIOPermissionAccess.Write,如果文件存在则异常; 4)Open打开现有文件,能力取决于FileAccess的值(Read,Write,ReadWrite),如果文件存在则异常; 5)OpenOrCreate打开或创建,FileAccess.Read--FileIOPermissionAccess.Read,FileAccess.Write/ReadWrite-- FileIOPermissionAccess.Write,FileAccess.Append--FileIOPermissionAccess.Append; 6)Truncate打开现有文件,文件一旦打开将被截断为零字节,试图从使用Truncate打开的文件中进行读取将异常 注:SqlDataReader使用后一定要关闭 2、写文本文件 string text = Console.ReadLine(); StreamWriter streamw = File.CreateText(@"E:\test3.txt"); streamw.WriteLine(text); streamw.Close(); 读取文本文件 string txt = ""; StreamReader sr = new StreamReader(@"E:\test.txt"); while (!sr.EndOfStream) { string str = sr.ReadLine(); txt += str + "\n"; } sr.Close(); Console.Write(txt); Console.Read(); (2)、产品的框架 1)Model类:对象层,制定对象的属性和方法; 2)IDAL类:接口层,定义在SQLDAL中需要使用的方法; 3)SQLDAL类:数据持久层,实现接口中的方法,用DBUtility类中包装的SQL方法操作数据库; 4)BLL类:业务逻辑层,定义调用SQLDAL类中的方法,被WEB类中的事件调用,联系数据持久层和WEB表示层,中间桥梁 ; 5)DALFactory类:创建接口类型的CREATE方法,在SQLDAL中创建接口对象; 6)DBUtility类:创建各种SQL方法,实现数据的调用; 7)WEB类:表示层,设计页面格式(HTML)和实现各种事件(JavaScript) (3)c#中执行sql语句时传递参数的小经验 1> 直接写入法: 例如: int Id =1; string Name="lui"; cmd.CommandText="insert into TUserLogin values("+Id+",'"+Name+"')"; 因为Id是数值,所以在传递的时候只需要在sql字符串中用"+Id+"即可实现,而Name是字符串,所以在传递的时候还需 要在"+Name+"两边各加一个单引号(')来 实现; 2>给命令对象添加参数法: 例如: int Id =1; string Name="lui"; cmd.CommandText="insert into TUserLogin values(@Id,@Name)"; //上条语句中直接在sql语句中写添加的参数名,不论参数类型都是如此. SqlParameter para=new SqlParameter("@Id",SqlDbType.int,4);//生成一个名字为@Id的参数,必须以@开头表 示是添加的参数,并设置其类型长度,类型长度与数据库中对应字段相同 para.Value=Id;//给参数赋值 cmd.Parameters.Add(para);//必须把参数变量添加到命令对象中去。 //以下类似 para=new SqlParameter("@Name",SqlDbType.VarChar,16); para.Value=Name; com.Parameters.Add(para); 然后就可以执行数据库操作了。
第1天 注释的应用 第2天 02_+号的应用 03变量的使用 C中的转义符 05交换量变量 07接收用户的信息 04个练习 06占位符 第3天 04逻辑运算符 05if结构 06习题 03bool类型 02Convert字符转换练习 01Convert字符装换 用户登录 第3天 Net第三天取余 第4天 01异常捕获 02练习 02异常捕获 03switch-case 04while循环 06练习 07while练习与do--while 08for 循环 12continue 09乘法口诀练习 10类型转换和方法转换 11tryparse练习 13三元表达式 第5天 00随机数 05数组 06数组的运用 06数组的运用:冒泡程序 07方法 01枚举 04结构 02枚举和int以及sting类型之间的转换 03枚举练习 第6天 01方法调用 判断是否为整数 yes或no 02方法练习求数组的和 03方法 out参数求数组的和 04 out参数练习 05 out练习 06 ref参数 07 ref 参数练习 08 params 可变参数 09方法的重载 10方法的递归 11方法练习 第7天 01面向对象 02 属性 03练习 第7天 01复习 02方法的调用问题 03判断闰年 04方法概念 05方法练习 06方法的3个练习 07out参数 08使用out参数做登陆 09自己动手写tryparse 10ref参数 11、ref练习 12params可变参数 13、方法的重载 14、方法的递归 15方法练习 第8天 01面向对象复习 02命名空间 03字符串的高级用法 04字符串练习 05继承 Driver Person Program Student Teacher 06继承的练习 第9天 00里氏转换 01里氏转换 M1 M2 M3 M4 person Program 02protected ArrayList集合 ArrayList集合练习 第10天 03_List泛型集合 04_Dictionary 05泛型集合练习 06文件流 FileStream 07StreamReader和StreamWriter 02 file类 01 path类。File.ReadAllBytes 第11天 02 抽象类 Animal Cat Dog Program 02-抽象类 Animal Program 03抽象类练习 04复习 06接口 05设计模式 06序列化 07partial部分类 08sealed密封类 01面向对象-多态 第12天 01接口 02接口的特点 03接口练习 03解决接口与方法重名问题 04收银系统 Banana BuDaZhe CangKu ....... 第13天 01第12天_接口 第14天 01MDI窗体设计 02PictureBox实现图片切换 03PictureBox和timer练习 第14天 MD5加密 03WindowsForms练习 05timer跑马灯练习 06timer闹钟练习不是完整的 08单选和多选练习 01MD5加密 04textBox控件显示输入的文本 02windows控件弹出窗体练习 07简单记事本应用 第15天 01浏览器控件 02下拉框日期选择器 02日期选择器控件 03双击播放音乐 04对话框练习 第16天 01播放音乐 01打开文件双击播放音乐 02线程 03线程执行带参数的方法-摇奖机 04创建服务端Socket(未实现) 04客户端的Socket(未实现) 05创建服务端的Socket 05创建客户端的Socket ConsoleApp1 第17天 02Command操作数据 03DataReader读取数据 04DataSet数据集 05DataAdapter数据适配 01第17天Connection数据库打开关闭 第18天 01DataGridView-表格数据控件 02DataGridView隐藏行列 03 DataGridView直接修改数据 04DataGridView当前行显示不同颜色 05分页 第19天 01进程 02进程 03FileStream文件流 03复制文件 03正则表达式 04正则表达式下载页面图片(未实现) 第20天 01创建XML文档 02对xml文档增删改查 03.2判断是否登录成功原版 03判断是否登录成功 04Xml增删改查 05Xml增删改查(更改的) 第21天 01为什么会有委托 02泛型委托 03多播委托 04使用委托进行窗体传值 05事件 06事件 07程序集的引用 07Common 08反射的常用函数 09用反射制作计算器 第22天 01 SqlConnection 数据库 02ConnectionStringBvilderDemo字符串创建器 03ConfigDemo 配置文件配置连接字符串 05UserDemon 04UserDemo 06DataImporting数据导入 07DataReader读取数据 第23天 第23天UserDemon用户登录

110,539

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧