[转载]写出优雅简明代码的论题集 -- Csharp(C#)篇[2]

mikel阅读(922)

[转载]写出优雅简明代码的论题集 — Csharp(C#)篇[2] – 喜乐的ASP.NET(Alex Song) – 博客园.

谢谢大家对本系列第一篇写出优雅简明代码的论题集 — Csharp(C#)篇[1]的回复和讨论,我相信针锋相对的辩论不仅有助于发现答案,更让我们了解问题后面的实质。

对程序员而言,我们的代码需要:

1. 在预算内实现需求,让用户可以使用 — 让自己或者公司可以赚到钱

2. 方便自己修改及日后维护

3. 方便别人修改及日后维护

4. 便于重复使用,为以后的开发节省时间

5. 让系统高效的运作

从美国商学院毕业的学生们掌握了很多相似的思维模式,这不仅有利于他们解决问题,更重要的是方便他们彼此之间沟通。– 换句话说,他们毕业后都安装上了相同的协议和一些可通用的接口,这样有一个基础平台可以让他们协同工作。

论题七:命名规范

也许有人认为没有必要再提这个问题,但在日常编码生活中,这的确是一个很重要的话题。

7.1  类名、方法、常数使用Pascal casing

public class MyClass
{
    const int DefaultNumber = 100;
    public void MyMethod()
    { }
}

7.2 局部变量,参数用camel casing

           partial void OnContactIdChanging(int value)
            {
                int number;

            }

7.3 interface 名字以I 开头

7.4 尽量不用单个字符命名变量,象 i 或者 t 。使用 index 或者 temp 之类代替。

7.5 将所有来自framework 的 namespace 放在前面,而后再放第三方或自定义的:

using System;
using System.Linq;
using System.Data.Linq;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel.DataAnnotations;
using CodeSmith.Data.Attributes;
using CodeSmith.Data.Rules;

论题八: 一个方法的参数不能超过5个,当多于5个时,应进行函数的拆分或者参数的封装。– 嚯嚯就像论题一样的规定

一些说明:不是为了给自己一个紧箍咒,而是在日常编程中,我们发现如果你写的方法不满足这样一个条件,一年后,就算是你自己也不太想去维护和修改,如果换成是其他程序员会对此更加的头痛,对吗?
论题九: 不要滥用注释,有些非常清晰明确的代码不需要注释

仅在必要的时候注释你的代码,不要太多,并且注释也要简单给力。
论题十: 不要把数值hard-code在代码中,使用const 来定义
论题十一: 不要使用””, 使用string.Empty

正确的:

string name = string.Empty;

不建议:

string name = "";

论题十二: 善于合并if

观察下面这段可爱的代码:

public bool Equals(CommentData obj) {
if (!CommentId.Equals(obj.CommentId)) return false;
if (!Comment.Equals(obj.Comment)) return false;
if (!CommentorId.Equals(obj.CommentorId)) return false;
return true;
}

如果我们写成这样会不会好些呢:

public bool Equals(CommentData obj) {
return CommentId == obj.CommentId &&
Comment.Equals(obj.Comment) &&
CommentorId == obj.CommentorId;
}

论题十三: 不断重构你的代码

当有新的需求或新改动的时候,可以拨一些时间来重构。 — 你可能突然发现,原来重构后的代码可以如此美丽。使用一些重构的插件,比如resharper可以使你事半功倍。

[转载]写出优雅简明代码的论题集 -- Csharp(C#)篇[1]

mikel阅读(1209)

[转载]写出优雅简明代码的论题集 — Csharp(C#)篇[1] – 喜乐的ASP.NET(Alex Song) – 博客园.

最近和一些朋友讨论如何写出优雅的代码,我们都很喜欢C#,所以以C#为例。主要一共有三位程序员在一起讨论,为简单起见我用ABC代表我们三个人。

有时候我们会针对一些代码进行讨论,有时候我们会提出一些观点,有时候我们会一起学习网上一些现有的博客,为了便于大家引用,我给每一个论题都编上号。

在很多情况下,我们的意见统一,那么我会给大家呈现我们的结论;但是有些情况我们有分歧。

你可以加入我们的讨论,我非常也希望能够获知你的意见,让我们一起茁壮成长!

好吧,让我们今天就开始。

论题一:函数越小越好!

象鼠

相信绝大部分程序员会认同这一点,维护一个超过100行的函数会让人抓狂。

我记得我以前修改过一个用cobol写的程序,一个文件超过10万行,我为了进行一个极其小的修改花了3天的时间,而且最后自己也不知道会不会造成什么严重的后果。– 这已经过去8年了,希望那段代码运行良好。

到底理想状态下,我们的函数应该不大于多少行?我们三个人的答案是:

A: 10 行

B: 15 行

C: 20 行

论题二:用 Linq 简化代码

Linq有时可以帮助我们写出一些非常“人性”的语句。

下面的这个函数是用于在数据库中插入新的评论:

        public static void Create(IEnumerable<CommentData> Comments, SqlConnection cn)
        {
            // validate params
            if (null == cn) throw new ArgumentNullException("cn");
            if (cn.State != ConnectionState.Open) throw new ArgumentException("Invalid parameter: connection is not open.", "cn");
            if (null == Comments) throw new ArgumentNullException("Comments");
            foreach (CommentData data in Comments)
            {
                if (data.CommentId.HasValue)
                    throw new ArgumentNullException("Create is only for saving new data.  Call save for existing data.", "data");
            }
....

其中foreach这一部分可以简化为:

           if (Comments.Any(data => data.CommentId.HasValue))
            {
                throw new ArgumentNullException("Create is only for saving new data.  Call save for existing data.", "data");
            }

在这一点上,我们存在分歧,A认为没有必要进行简化,因为原来的已经很明确了;但B认为简化后的代码可读性更强,看上去更加直接。

希望每个人都已经知道C#的这个用法了,直接上一些代码:

3.1

原始代码:

List<int> idsToFind = new List<int>();
idsToFind.Add(1);
idsToFind.Add(2);

修改后:

List<int> idsToFind = new List<int> {1, 2};

3.2

原始代码:

var startingPoint = new Point();
startingPoint.X = 5;
startingPoint.Y = 13;

修改后:

var startingPoint = new Point() { X = 5, Y = 13 };

论题四:运用 ?:和??

据说,有些公司会拿这个来测试入门的程序员:

4.1

原始代码:

if (c != null)
    System.Console.WriteLine(c.Name);
else
    System.Console.WriteLine("List element has null value.");

修改后:

System.Console.WriteLine(c != null ? c.Name : "List element has null value.");

4.2

原始代码:

string name = value;   
if (value == null)
{
name = string.Empty;
}

修改后:

string name = (value != null) ? value : string.Empty;

还可以更简单,变成:

string name = value ?? string.Empty;

论题五: 运用AS

原始代码:

if (employee is SalariedEmployee)

{
    var salEmp = (SalariedEmployee)employee;
    pay = salEmp.WeeklySalary;
    // ...
}

修改后:

var salEmployee = employee as SalariedEmployee;
if (salEmployee != null)
{
   pay = salEmployee.WeeklySalary;
    // ...
}

论题六: 运用 using

using首次出现是在visual studio 2005 中,在这以前,很多程序员晕倒在了释放资源的逻辑中。

使用using语句实际上生成的IL代码中是一个try, finally代码块,在finally代码块里释放资源。

原始代码:

public IEnumerable<Order> GetOrders()

{
    var orders = new List<Order>(); 
    var con = new SqlConnection("some connection string");
    var cmd = new SqlCommand("select * from orders", con);
    var rs = cmd.ExecuteReader(); 
    while (rs.Read())

    {

        // ...

    } 
    rs.Dispose();
    cmd.Dispose();
    con.Dispose(); 
    return orders;
} 

这是一段非常丑陋的代码,我们完全迷失在dispose群中,什么时候要调用哪个dispose啊? 天哪? 如果我们用 finally, 可以将代码写为:

public IEnumerable<Order> GetOrders()

{

    SqlConnection con = null;

    SqlCommand cmd = null;

    SqlDataReader rs = null;

    var orders = new List<Order>();

    try

    {

        con = new SqlConnection("some connection string");

        cmd = new SqlCommand("select * from orders", con);

        rs = cmd.ExecuteReader();

        while (rs.Read())

        {

            // ...

        }

    }

    finally

    {

        rs.Dispose();

        cmd.Dispose();

        con.Dispose();

    }

    return orders;

}

看看using到底给我们带来了什么:

public IEnumerable<Order> GetOrders()

{

    var orders = new List<Order>(); 
   using (var con = new SqlConnection("some connection string"))
    {
        using (var cmd = new SqlCommand("select * from orders", con))
        {
            using (var rs = cmd.ExecuteReader())
            {
                while (rs.Read())
                {

                    // ...

                }

            }

        }

    } 
    return orders;

好多了,对吗? 完全不用再用那一堆的try/finally 代码了,也不用使用一堆的null,为了使代码更轻巧,让我们再做小小修改:

      public IEnumerable<Order> GetOrders()
{

    var orders = new List<Order>(); 

    using (var con = new SqlConnection("some connection string"))
    using (var cmd = new SqlCommand("select * from orders", con))
    using (var rs = cmd.ExecuteReader())
    {
        while (rs.Read())
        {
           // ...
        }
    } 
    return orders;

} 

[转载]C#高效编程话题集1(每期10话题)

mikel阅读(848)

[转载]C#高效编程话题集1(每期10话题) – 不如来编码-luminji’s web – 博客园.

近来在小组C#快速成长团队 讨论了若干话题,有些感觉不错,特总结与大家分享。
当然,所谓话题,重点在于进行讨论,是否是最佳实践也属于大家的个人之见。以下观点若有差错,尽情蹂躏。
1:String str1 = “str1”+ 9; 和String str2 = “str2”+ 9.ToString(); 哪个效率高
可以知道“str1”+ 9,在运行时会完成一次装箱行为。9.ToString(),没有发生装箱行为,Int类型的ToString()方法的实际原型为:

public override String ToString() { return Number.FormatInt32(m_value, null, NumberFormatInfo.CurrentInfo); }

可能有人会问,那是不是原型中的Number.FormatInt32方法会发生装箱行为呢?实际Number.FormatInt32方法是一个非托管的方法,原型如下:

[MethodImpl(MethodImplOptions.InternalCall), SecurityCritical] public static extern string FormatInt32(int value, string format, NumberFormatInfo info);

它通过直接操作内存来进行int到string的转换,效率要比装箱高很多。
所以,答案是:后者
装箱为什么会带来性能损耗,因为它内部发生了太多事情:
1:首先,为值类型在托管堆中分配内存。内存总量除了值类型本身所分配的内存外,还要加上类型对象指针和同步块索引;
2:值类型的值复制到新分配的堆内存;
3:返回已经成为引用类型的对象的地址;
2:as,is转型比强制转型的优势

优势在于as,is 不抛出异常,如果转型失败,则返回null

强制转型则会抛出异常,导致代码必须处理异常,效率低。

值得注意的是,as只能转型基本类型,对于基本类别如int等的转型,只能使用强制转型或is。


3:readonly和const的区别或者说哪个更好

1:const天然就是static的,所以不能用static修饰;readonly无此限制;
2:const只能修饰基元类型;readonly无此限制;
3:const是编译期常量;readonly为运行期常量,其初始值除了在初始化器还可以在类型的构造函数中设定;
4:const经编译后,以实际值代替了变量(可查看IL验证),效率显然要高一些,可用到关键算法中,除此之外,与readonly比没有任何优势。
4:初始化器和构造器的异同
初始化器实际是语法糖,经编译后,它在构造函数的最开始执行。也就是说,初始化器可以理解为构造函数的一部分。
5:枚举在使用中的注意事项

1:如果不指定枚举的零值,会带来什么问题;

static Week week; static void Main(string[] args) { Console.WriteLine(week); }

即使未给week赋值,也会打印出零值。2:如果为枚举中的元素指定了相同的值,又会带来什么问题。

会导致相等型比较的时候出现与预期不符的结果
3:建议不给枚举显式指定值,但是如果枚举用于位运算则要为其元素指定2的指数幂值。
6:为什么LINQ语句都要开始于from而不是select
显而易见的原因是为了智能感知,要让他在输入LINQ查询的时候起作用,from子句就必须在最前面;如:
var AllCustomers = from Customer in db.Customers
select new { Customer.ContactName, Customer.Country };
7:dynamic可以用它来简化反射。
使用反射,调用方代码:

DynamicSample dynamicSample = new DynamicSample(); var addMethod = typeof(DynamicSample).GetMethod("Add"); int re = (int)addMethod.Invoke(dynamicSample, new object[] { 1, 2 });

在使用dynamic后,我们的代码看上去更简洁了,并且在可控的范围内减少了一次拆箱的机会:

dynamic dynamicSample2 = new DynamicSample(); int re2 = dynamicSample2.Add(1, 2);
8:foreach不能替代for的原因
1: 首先,对集合的每次增删操作(是不是全部集合?不得而知,但是起码是绝大部分集合),都会让集合的version字段+1,foreach采用的是迭代器 模式,每次迭代的时候都要判断version是不是保持一致,如果不一致,则抛出异常。而for没有这方面的限制。所以,采用

List<int> list = new List<int>() { 0, 1, 2, 3 }; foreach (int item in list) { list.Remove(item); Console.WriteLine(item.ToString()); }
会抛出异常,而改为for则不会。这是for不能被foreach取代叼的最重要原因。

2:foreach默认调用集合的迭代器的Dispose方法,如果该迭代器继承了IDispose方法的话。

9:区别IComparable<T>和IComparer<T>

前者IComparable<T>为类提供默认的比较器,而IComparer<T>可以为集合类提供更多的比较器。具体查看http://www.cnblogs.com/luminji/archive/2010/09/30/1839038.html
10:LINQ和比较器及迭代器优缺点比较

要进行排序和比较,传统的方式,存在两个问题:
1:可扩展性太低,如果存在新的排序要求,就得实现新的比较器;
2:对代码的侵入性太高,为类型继承了接口,增加了新的方法;
可参见博文的讨论:http://www.cnblogs.com/luminji/archive/2011/02/17/1956723.html

在我们自己的代码中强烈建议你利用LINQ带来便捷性,但我们仍需掌握比较器、迭代器、索引器的原理,以便我们更好地理解LINQ的思想,写出更加高质量的代码。

[转载]URL的井号

mikel阅读(1081)

[转载]URL的井号_IT新闻_博客园.

去年9月,twitter改版。

一个显著变化,就是URL加入了”#!”符号。比如,改版前的用户主页网址为

http://twitter.com/username

改版后,就变成了

http://twitter.com/#!/username

这是主流网站第一次将”#”大规模用于重要URL中。这表明井号(Hash)的作用正在被重新认识。本文根据HttpWatch的文章,整理与井号有关的所有重要知识点。

一、#的涵义

#代表网页中的一个位置。其右面的字符,就是该位置的标识符。比如,

http://www.example.com/index.html#print

就代表网页index.html的print位置。浏览器读取这个URL后,会自动将print位置滚动至可视区域。

为网页位置指定标识符,有两个方法。一是使用锚点,比如<a name=”print”></a>,二是使用id属性,比如<div id=”print”>。

二、HTTP请求不包括#

#是用来指导浏览器动作的,对服务器端完全无用。所以,HTTP请求中不包括#。

比如,访问下面的网址,

http://www.example.com/index.html#print

浏览器实际发出的请求是这样的:

GET /index.html HTTP/1.1

Host: www.example.com

可以看到,只是请求index.html,根本没有”#print”的部分。

三、#后的字符

在第一个#后面出现的任何字符,都会被浏览器解读为位置标识符。这意味着,这些字符都不会被发送到服务器端。

比如,下面URL的原意是指定一个颜色值:

http://www.example.com/?color=#fff

但是,浏览器实际发出的请求是:

GET /?color= HTTP/1.1

Host: www.example.com

可以看到,”#fff”被省略了。只有将#转码为%23,浏览器才会将其作为实义字符处理。也就是说,上面的网址应该被写成:

http://example.com/?color=%23fff

四、改变#不触发网页重载

单单改变#后的部分,浏览器只会滚动到相应位置,不会重新加载网页。

比如,从

http://www.example.com/index.html#location1

改成

http://www.example.com/index.html#location2

浏览器不会重新向服务器请求index.html。

五、改变#会改变浏览器的访问历史

每一次改变#后的部分,都会在浏览器的访问历史中增加一个记录,使用”后退”按钮,就可以回到上一个位置。

这对于ajax应用程序特别有用,可以用不同的#值,表示不同的访问状态,然后向用户给出可以访问某个状态的链接。

值得注意的是,上述规则对IE 6和IE 7不成立,它们不会因为#的改变而增加历史记录。

六、window.location.hash读取#值

window.location.hash这个属性可读可写。读取时,可以用来判断网页状态是否改变;写入时,则会在不重载网页的前提下,创造一条访问历史记录。

七、onhashchange事件

这是一个HTML 5新增的事件,当#值发生变化时,就会触发这个事件。IE8+、Firefox 3.6+、Chrome 5+、Safari 4.0+支持该事件。

它的使用方法有三种:

window.onhashchange = func;

<body onhashchange=”func();”>

window.addEventListener(“hashchange”, func, false);

对于不支持onhashchange的浏览器,可以用setInterval监控location.hash的变化。

八、Google抓取#的机制

默认情况下,Google的网络蜘蛛忽视URL的#部分。

但是,Google还规定,如果你希望Ajax生成的内容被浏览引擎读取,那么URL中可以使用”#!”,Google会自动将其后面的内容转成查询字符串_escaped_fragment_的值。

比如,Google发现新版twitter的URL如下:

http://twitter.com/#!/username

就会自动抓取另一个URL:

http://twitter.com/?_escaped_fragment_=/username

通过这种机制,Google就可以索引动态的Ajax内容。

[转载]深度解析Android样式

mikel阅读(700)

[转载]深度解析安卓样式 – 一尘 – 博客园.

如果你曾经是一名 WEB前台设计师,如果你曾经有过设计的功底,那么你很荣幸,如果你切到安卓平台中,以前的知识和经验都能很好的移植到安卓平台中。本人以为,学习是一个 长期的积累过程,经验很重要,为什么有的人不管做神马生意都赚钱,因为他有经验,经验加上变通,就是智慧。

布 局是根本,不管在WEB设计还是在手机客户端设计中,都是如此。如果一开始局就没有布好,就算你的细节做得再精美,到头来还是要重构。相比传统WEB设计 中的布局,安卓平台一样都不少,只是WEB设计的层布局,在安卓中有了个新的叫法,叫帧布局。布局在本篇中不是重点,因为和WEB中的概念几乎一样,所以 一笔带过。

说 实话,我还是比较喜欢WEB设计中的样式命名规范,简单,易用,最主要的是WEB的样式很好管理,不像安卓样式文件分得很细,看起来比较零乱。如果你研究 过SDK的设计方式,你会发现一个按钮的样式,分得很细,有btn_default.xml,btn_default_small.xml等二十几个样式 文件。

下面我们模仿SDK的设计方式,自定义一个按钮样式文件btn_default.xml,包含非焦点,焦点,pressed三种不同状态。

<!--?xml version="1.0" encoding="utf-8"?-->





selector可以理解为状态切换器,不同的状态下切换不同的样式,在传统WEB设计中就是伪类hover。shape意为定义按钮的形状。

样式的引用很简单,安卓统一把样式文件作为她的一种资源,下面是样式的使用方式。

<button>

</button>

效果

总结:

整体来说,安卓的样式设计非常的灵活,WEB设计中的大部分概念都适用于安卓平台,包括样式的继承概念。

[转载]深度解析Android样式

mikel阅读(883)

[转载]深度解析安卓样式 – 一尘 – 博客园.

如果你曾经是一名 WEB前台设计师,如果你曾经有过设计的功底,那么你很荣幸,如果你切到安卓平台中,以前的知识和经验都能很好的移植到安卓平台中。本人以为,学习是一个 长期的积累过程,经验很重要,为什么有的人不管做神马生意都赚钱,因为他有经验,经验加上变通,就是智慧。

布 局是根本,不管在WEB设计还是在手机客户端设计中,都是如此。如果一开始局就没有布好,就算你的细节做得再精美,到头来还是要重构。相比传统WEB设计 中的布局,安卓平台一样都不少,只是WEB设计的层布局,在安卓中有了个新的叫法,叫帧布局。布局在本篇中不是重点,因为和WEB中的概念几乎一样,所以 一笔带过。

说 实话,我还是比较喜欢WEB设计中的样式命名规范,简单,易用,最主要的是WEB的样式很好管理,不像安卓样式文件分得很细,看起来比较零乱。如果你研究 过SDK的设计方式,你会发现一个按钮的样式,分得很细,有btn_default.xml,btn_default_small.xml等二十几个样式 文件。

下面我们模仿SDK的设计方式,自定义一个按钮样式文件btn_default.xml,包含非焦点,焦点,pressed三种不同状态。

<!--?xml version="1.0" encoding="utf-8"?-->





selector可以理解为状态切换器,不同的状态下切换不同的样式,在传统WEB设计中就是伪类hover。shape意为定义按钮的形状。

样式的引用很简单,安卓统一把样式文件作为她的一种资源,下面是样式的使用方式。

<button>

</button>

效果

总结:

整体来说,安卓的样式设计非常的灵活,WEB设计中的大部分概念都适用于安卓平台,包括样式的继承概念。

[转载]在Android中实现多线程断点下载(连载一)

mikel阅读(1070)

[转载](Android小应用)在Android中实现多线程断点下载(连载一) – And_He – 博客园.

当我们从Internet中下载一个文件时,有的文件比较大,比如音乐或视频文件,下载的话需要比较长的时间,当我们在下载过程中,如果手机没电了 或者其它原因,使当前的下载中断了,按照一般的程序,当下次下载又需要从新开始,这里我们来实现多纯程断点下载,当下载中断了,下次启动的时候还会接着下 载,有点像我们的迅雷了……

首先呢,我们先不急着建Android应用,先建一个Java项目,测试一下下

然后在这个项目里面建一个测试用例

包都可以不填,因为只是测试,不是真正的应用,偷懒了……

OK,接着写代码

package junit.test;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import org.junit.Test;

public class InternetTest {
/**
* 读取输入流并返回数据
* @param input
* @return
* @throws Exception
*/
public byte[] readStream(InputStream input) throws Exception{
byte[] buffer = new byte[1024];
ByteArrayOutputStream output = new ByteArrayOutputStream();
int len = -1;
while((len=input.read(buffer))!=-1){
output.write(buffer, 0, len);
}
input.close();
output.close();
return output.toByteArray();
}

/**
* 从网络上下载图片
* @throws Exception
*/

@Test
public void getImage()throws Exception{
String urlPath = "http://photocdn.sohu.com/20110401/Img280097999.jpg";//在网络上随便找一张图片的链接
URL url = new URL(urlPath);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();//返回一个连接对象
conn.setRequestMethod("GET");//设置请求方式
conn.setConnectTimeout(6*1000);//设置连接超时,这里可以不用设置,但是在android应用中应该设置超时时间
if (conn.getResponseCode()==200) {
InputStream input = conn.getInputStream();
byte[] data = readStream(input);
File file = new File("test.jpg");
FileOutputStream output = new FileOutputStream(file);
output.write(data);
output.close();
}
}

/**
* 得到网页html
* @throws Exception
*/
@Test
public void getHtml()throws Exception{
String urlPath = "http://www.baidu.com";
URL url = new URL(urlPath);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(6*1000);
if (conn.getResponseCode()==200) {
InputStream input = conn.getInputStream();
byte[] data = readStream(input);
System.out.println(new String(data));//直接输出到控制台
}
}
}

然后测试,是否有预期的结果,如果有,继续下面,如果没有,再看看是不是哪儿错了

然后再建一个测试类,实现多线程下载,以下载一首mp3为例

package junit.test;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;

import org.junit.Test;

public class DownloaderTest {
/**
* 读取输入流并返回数据
* @param input
* @return
* @throws Exception
*/
public byte[] readStream(InputStream input) throws Exception {
ByteArrayOutputStream output = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = -1;
while ((len = input.read(buffer)) != -1) {
output.write(buffer, 0, len);
}
input.close();
output.close();
return output.toByteArray();
}

@Test
public void downloader() throws Exception {
String urlPath = "http://dl.toofiles.com/vaaoje/audios/qbd.mp3";
URL url = new URL(urlPath);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
int threadsize = 3;//定义线程数
int filesize = conn.getContentLength();// 获取文件大小
int block = filesize / threadsize + 1;// 每条线程下载的数量
conn.disconnect();
File file = new File("千百度.mp3");
RandomAccessFile randfile = new RandomAccessFile(file, "rw");//RandomAccessFile可以指定从文件的什么位置写入数据
for(int i=0;i int startposition = i * block;//记录每条线程的开始位置
RandomAccessFile threadfile = new RandomAccessFile(file, "rw");
threadfile.seek(startposition);//从文件的什么位置开始写入
new Thread(new DownloadThread(i,url,startposition,threadfile,block)).start();
}
/*
* 设置一个标志,当输入q的时候停止主线程
*/
byte b[] = new byte[1];
System.in.read(b);
while(!('q'==b[0])){
Thread.sleep(3*1000);
}
}
private class DownloadThread implements Runnable{

private int id ;
private URL url;
private int startposition;
private RandomAccessFile threadfile;
private int block;
public DownloadThread(int id ,URL url,int startposition,RandomAccessFile threadfile,int block){
this.id=id;
this.url=url;
this.startposition=startposition;
this.threadfile=threadfile;
this.block=block;
}
@Override
public void run() {
// TODO Auto-generated method stub
try {
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Range", "bytes="+startposition+"-");
conn.setConnectTimeout(6 * 1000);
InputStream input = conn.getInputStream();
byte[] buffer = new byte[1024];
int len = -1;
int readfilesize = 0;//记录下载的文件大小
while (readfilesize threadfile.write(buffer, 0, len);
readfilesize += len;//累计下载的文件大小
}
threadfile.close();
conn.disconnect();
System.out.println((this.id+1)+"线程下载完成");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

}
}

运行此测试类,如果没有异常抛出的话就成功了……

多线程下载的核心代码已经完成,下面结合到Android应用中,我们还得用到SQLite知识,要实现多线程下载,当中断的时候,我们系统会记录一个下载位置,我们把它保存在数据库中,第二次运行的时候再从数据库中读取出来,假设大家都有SQLite方面的知识……

接下来应该建Android项目了

连载中……

[转载]分享30套精美的Web和手机开发UI素材包

mikel阅读(852)

[转载]分享30套精美的Web和手机开发UI素材包 – 梦想天空 – 博客园.

本文与大家分享一批精美的Web和手机UI元素和资源包,如果你正在开发一个手机项目,相信这些资源一定能帮上你的大忙,其它朋友也可以收藏起来,说不定以后会用到的:)


(编译来源:梦想天空 原文来自:30+ Free Web, Mobile UI Element Kits and Stencils for Designers

[转载]分享30套精美的Web和手机开发UI素材包

mikel阅读(791)

[转载]分享30套精美的Web和手机开发UI素材包 – 梦想天空 – 博客园.

本文与大家分享一批精美的Web和手机UI元素和资源包,如果你正在开发一个手机项目,相信这些资源一定能帮上你的大忙,其它朋友也可以收藏起来,说不定以后会用到的:)


(编译来源:梦想天空 原文来自:30+ Free Web, Mobile UI Element Kits and Stencils for Designers

[转载]Asp.net中如何删除cookie?

mikel阅读(802)

[转载]Asp.net中如何删除cookie? – goody9807 – 博客园.

不能直接删除用户计算机中的 Cookie。但是,可以通过将 Cookie 的到期日期设置为过去的日期,让用户的浏览器来删除 Cookie。当用户下一次向设置该 Cookie 的域或路径内的页发出请求时,浏览器将确定该 Cookie 已到期并将其移除。

调用 Cookies集合的 Remove方法可从服务器端的集合中移除 Cookie,使 Cookie 不会被发送至客户端。但是,如果客户端已存在 Cookie,则

向 Cookie 分配已过去的到期日期
  1. 确定 Cookie 是否存在,如果存在则创建同名的新 Cookie。
  2. 将 Cookie 的到期日期设置为过去的某一时间。
  3. 将 Cookie 添加到 Cookies 集合对象。

    下面的代码示例演示如何为 Cookie 设置已过去的到期日期。

    Visual Basic
    If (Not Request.Cookies(“UserPreferences1”) Is Nothing) Then
    Dim myCookie As HttpCookie
    myCookie = New HttpCookie(“UserPreferences1”)
    myCookie.Expires = DateTime.Now.AddDays(-1D)
    Response.Cookies.Add(myCookie)
    End If
    if (Request.Cookies[“UserSettings”] != null)
    {
    HttpCookie myCookie = new HttpCookie(“UserSettings”);
    myCookie.Expires = DateTime.Now.AddDays(-1d);
    Response.Cookies.Add(myCookie);
    }

编译代码

此示例需要:

  1. 一个 ASP.NET 网页。
  2. 一个先前编写的名为 UserSettings 的 Cookie,

可靠编程

出于安全原因,您只能读取属于同一域的页所设置的 Cookie。如果已经设置 Cookie 的 Path属性,则该 Cookie 也只能用于该域路径内的页和子文件夹。

在读取特定 Cookie 值时,请测试该 Cookie 是否存在以及它是否具有值,否则将发生异常。